<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>UzzzzZ</title><link>https://uzzju.com/</link><description>wish</description><item><title>Nacos RCE漏洞分析</title><link>https://uzzju.com/post/87.java</link><description>&lt;h1 id=&quot;h1-u6F0Fu6D1Eu7B80u4ECB&quot;&gt;&lt;a name=&quot;漏洞简介&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞简介&lt;/h1&gt;&lt;p&gt;Nacos 是一个开源的、易于使用的动态服务发现、配置和服务管理平台，用于构建云原生应用。它提供了一套简单易用的特性集，用于服务发现和服务健康监测，以及动态配置服务、服务元数据和流量管理。&lt;/p&gt;
&lt;h1 id=&quot;h1-u6F0Fu6D1Eu63CFu8FF0&quot;&gt;&lt;a name=&quot;漏洞描述&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞描述&lt;/h1&gt;&lt;p&gt;RCE（Remote Code Execution，远程代码执行）漏洞是指攻击者能够在远程服务器上执行任意代码的安全漏洞。此类漏洞通常会让攻击者完全控制受影响的系统，导致严重的安全问题。&lt;/p&gt;
&lt;h1 id=&quot;h1-u5F71u54CDu8303u56F4&quot;&gt;&lt;a name=&quot;影响范围&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;影响范围&lt;/h1&gt;&lt;p&gt;Alibaba-Nacos:version&amp;lt;=2.3.2受影晌。&lt;/p&gt;
&lt;h1 id=&quot;h1-u6F0Fu6D1Eu590Du73B0&quot;&gt;&lt;a name=&quot;漏洞复现&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞复现&lt;/h1&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191035005.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;用Github公开的exp可以复现该漏洞。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;h1-u6F0Fu6D1Eu5206u6790&quot;&gt;&lt;a name=&quot;漏洞分析&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞分析&lt;/h1&gt;&lt;p&gt;从exp可以看出来，本次漏洞涉及2个接口&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/nacos/v1/cs/ops/derby&lt;/li&gt;&lt;li&gt;/nacos/v1/cs/ops/data/removal&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191038426.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;这里是存在2个漏洞，1个是SQL注入，1个是文件上传，也就是条件竞争。&lt;br&gt;由于Nacos默认部署是没有鉴权的，在未配置的情况下，这里也可以未授权。&lt;/p&gt;
&lt;p&gt;SQL注入漏洞来源于：&lt;a href=&quot;https://github.com/alibaba/nacos/issues/10613&quot;&gt;https://github.com/alibaba/nacos/issues/10613&lt;/a&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191054648.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;这里主要比较有意思的是这个文件上传的过程&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191110624.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;核心在com.alibaba.nacos.core.utils.WebUtils#onFileUpload，这里在创建文件之后&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191111210.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;会调用Consumer.accept，发布一个处理逻辑，表示文件处理开始。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191112871.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;随后在dataImport中，针对file对象里面的内容进行遍历，随后执行SQL。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191112535.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;核心的逻辑就在这，&lt;br&gt;前面的模型是，生产者，和消费者，那么Consumer这个消费者，执行前是同步的，但是在调用文件处理的时候，调用了一个异步处理，但是又没有等待异步处理完毕，然后就执行了finally里面的删除&lt;code&gt;DiskUtils.deleteQuietly(tmpFile);&lt;/code&gt;删除了临时文件，这就导致了会发生在处理时找不到文件的问题。&lt;br&gt;例如下面这张图这样。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191118368.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;那么只要让这里执行阻塞就可以了，通过大量的上传，让这里阻塞，就能够让异步执行的时候，有几率找到恶意的文件，然后进行SQLBatch导入。&lt;/p&gt;
&lt;p&gt;com.alibaba.nacos.core.persistence.DistributedDatabaseOperateImpl#dataImport 主要是把文件内容拿出来然后执行batchSQL&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191129587.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;比如，成功的情况下，就会把SQL取出来，加入到batchSQL中&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191132318.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;随后通过doDataImport导入&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191133644.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407191134041.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;所以漏洞原理可以概括为： 有这样一个功能，初衷是希望用户能够上传文件，且文件被异步的处理（我个人认为这里功能也有bug，因为就算正常用户去上传，也会执行finally导致文件删除，文件上传失败），通过条件竞争的方式，大量上传请求，导致这里阻塞，生产者创建了文件，但是还没来得及删，异步开始处理，导致把恶意的derby sql导入了数据库，导致了UDF问题。&lt;/p&gt;
&lt;h2 id=&quot;h2-u7591u95EEu89E3u7B54&quot;&gt;&lt;a name=&quot;疑问解答&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;疑问解答&lt;/h2&gt;&lt;p&gt;1、为什么可以UDF&lt;br&gt;我影响中，默认部署，想要利用MYSQL的UDF，好像不是一件简单的事情，需要有一些配置条件，在看到这个漏洞的时候可以UDF执行命令，这是让我比较疑惑的。&lt;br&gt;其实主要是因为，默认情况下，使用的是apache的derby数据库，这是一个Java写的数据库，&lt;br&gt;derby数据库是支持调用Java的方法的。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;CALL SQLJ.INSTALL_JAR(&amp;#39;file:///path/to/mypackage/MyFunctions.jar&amp;#39;, &amp;#39;APP.MyFunctionsJar&amp;#39;, 0);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;也就是poc中的这一段&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;post_sql = &amp;quot;&amp;quot;&amp;quot;CALL sqlj.install_jar(&amp;#39;{service}&amp;#39;, &amp;#39;NACOS.{id}&amp;#39;, 0)\n  
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY(&amp;#39;derby.database.classpath&amp;#39;,&amp;#39;NACOS.{id}&amp;#39;)\n  
CREATE FUNCTION S_EXAMPLE_{id}( PARAM VARCHAR(2000)) RETURNS VARCHAR(2000) PARAMETER STYLE JAVA NO SQL LANGUAGE JAVA EXTERNAL NAME &amp;#39;test.poc.Example.exec&amp;#39;\n&amp;quot;&amp;quot;&amp;quot;.format(id=id,service=service);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2、这个漏洞是怎么来的？&lt;br&gt;利用条件竞争实现UDF的导入创建，随后利用一个以往发现的功能去执行SQL，导致了RCE。&lt;/p&gt;
&lt;h1 id=&quot;h1-u6F0Fu6D1Eu6392u67E5&quot;&gt;&lt;a name=&quot;漏洞排查&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞排查&lt;/h1&gt;&lt;p&gt;1、影响版本&lt;br&gt;Alibaba-Nacos:version&amp;lt;=2.3.2受影晌。&lt;/p&gt;
</description><pubDate>Fri, 19 Jul 2024 14:35:00 +0800</pubDate></item><item><title>云网OA8.0 updateUiSetup接口存在未授权FastJSON RCE</title><link>https://uzzju.com/post/86.java</link><description>&lt;h1 id=&quot;h1--oa8-0-updateuisetup-fastjson-rce&quot;&gt;&lt;a name=&quot;云网OA8.0 updateUiSetup接口存在未授权FastJSON RCE&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;云网OA8.0 updateUiSetup接口存在未授权FastJSON RCE&lt;/h1&gt;&lt;h1 id=&quot;h1-u57FAu672Cu4FE1u606F&quot;&gt;&lt;a name=&quot;基本信息&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;基本信息&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;Gitee地址：&lt;a href=&quot;https://gitee.com/bestfeng/oa_git_free&quot;&gt;https://gitee.com/bestfeng/oa_git_free&lt;/a&gt;&lt;/li&gt;&lt;li&gt;部署文档：&lt;a href=&quot;http://partner.yimihome.com/static/index.html#/index/idea_deploy8&quot;&gt;http://partner.yimihome.com/static/index.html#/index/idea_deploy8&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h1 id=&quot;h1-u529Fu80FDu70B9&quot;&gt;&lt;a name=&quot;功能点&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;功能点&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;src/main/java/com/cloudweb/oa/controller/ApplicationController.java&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202406181720313.png&quot; alt=&quot;image-20240618172021275&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202406181642876.png&quot; alt=&quot;image-20240618164259851&quot;&gt;&lt;/p&gt;
&lt;p&gt;低版本FastJSON&lt;/p&gt;
&lt;p&gt;低版本FastJSON&lt;/p&gt;
&lt;p&gt;为什么会存在未授权，因为Filter的配置，这个oa，对于filter chain有点多，有基于spring security，也有原生的Dofilter，感觉偶尔的Chain会乱&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202406181726335.png&quot; alt=&quot;image-20240618172612295&quot;&gt; &lt;/p&gt;
&lt;p&gt;这里不登录也是可以访问的&lt;/p&gt;
&lt;h1 id=&quot;h1-u6F0Fu6D1Eu590Du73B0&quot;&gt;&lt;a name=&quot;漏洞复现&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞复现&lt;/h1&gt;&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;POST /oa/setup/updateUiSetup?applicationCode=1&amp;amp;uiSetup=payloadHTTP/1.1
Host: 127.0.0.1:8880
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Priority: u=1
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: application/json
Content-Length: 18
cmd:whoami

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202406181643232.png&quot; alt=&quot;image-20240618164335202&quot;&gt;&lt;/p&gt;
</description><pubDate>Fri, 12 Jul 2024 10:22:47 +0800</pubDate></item><item><title>泛微E-Cology9 getFileViewUrl SSRF漏洞分析</title><link>https://uzzju.com/post/85.java</link><description>&lt;h1 id=&quot;h1-u6F0Fu6D1Eu63CFu8FF0&quot;&gt;&lt;a name=&quot;漏洞描述&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞描述&lt;/h1&gt;&lt;p&gt;泛微协同管理应用平台e-cology是一套兼具企业信息门户、知识文档管理、工作流程管理、人力资源管理、客户关系管理、项目管理、财务管理、资产管理、供应链管理、数据中心功能的企业大型协同管理平台。泛微E-Cology getFileViewUrl 接口处存在服务器请求伪造漏洞，未经身份验证的远程攻击者利用此漏洞扫描服务器所在的内网或本地端口，获取服务的banner信息，窥探网络结构，甚至对内网或本地运行的应用程序发起攻击，获取服务器内部敏感配置，造成信息泄露。&lt;/p&gt;
&lt;h1 id=&quot;h1-u5F71u54CDu6CDBu5FAE&quot;&gt;&lt;a name=&quot;影响泛微&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;影响泛微&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;上海泛微网络科技股份有限公司-泛微协同管理应用平台 E-cology9&lt;ul&gt;
&lt;li&gt;已复现版本： 2303.02&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;h1 id=&quot;h1-u6F0Fu6D1Eu590Du73B0&quot;&gt;&lt;a name=&quot;漏洞复现&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞复现&lt;/h1&gt;&lt;p&gt;poc&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&amp;quot;file_id&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;file_name&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;download_url&amp;quot;:&amp;quot;xxxx poc url&amp;quot;,
&amp;quot;client_type&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;isCopy&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;user_id&amp;quot;:&amp;quot;1&amp;quot;}&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;POST /api/doc/mobile/fileview/getFileViewUrl HTTP/1.1
Host: 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:127.0) Gecko/20100101 Firefox/127.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Referer: 
Content-Type: application/json
X-Requested-With: XMLHttpRequest
Origin:
Connection: keep-alive
Cookie: 
Priority: u=4
Content-Length: 135

{&amp;quot;file_id&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;file_name&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;download_url&amp;quot;:&amp;quot;xxxx&amp;quot;,
&amp;quot;client_type&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;isCopy&amp;quot;:&amp;quot;1&amp;quot;,
&amp;quot;user_id&amp;quot;:&amp;quot;1&amp;quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140358.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;h1-u6F0Fu6D1Eu5206u6790&quot;&gt;&lt;a name=&quot;漏洞分析&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;漏洞分析&lt;/h1&gt;&lt;p&gt;com.api.doc.mobile.fileview.web.FileViewAction#getFileViewUrl&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140359.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;把JSON转为Map后，给到Execute&lt;br&gt;com.api.doc.mobile.fileview.cmd.FileViewCmd#execute&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140360.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;其中获取的DownloadUrl，就直接通过Map获取，给到null2String3&lt;br&gt;下面主要是判断Prop下的一些配置&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140361.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;需要满足第一个if，需要配置中的数字为1&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140362.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;我这边都没有配置，所以会走下面的else，不管这里走哪个分支，都可以到对应的Sink，造成SSRF&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140363.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;s3这个参数是我们的可控污点。&lt;br&gt;com.api.doc.mobile.fileview.cmd.FileViewCmd#getSocialFileViewUrlForYz(java.lang.String, java.lang.String, java.lang.String, int, java.util.Map&amp;lt;java.lang.String,java.lang.String&amp;gt;)&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140364.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;0，1，参数不为空的情况下，则会进入这里的流程。&lt;br&gt;com.api.doc.detail.util.ImageConvertUtil#doConvertForSocial(java.lang.String, java.lang.String, int, java.util.Map&amp;lt;java.lang.String,java.lang.String&amp;gt;)&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140365.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;我们进入com.api.doc.detail.util.ImageConvertUtil#doConvert&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140366.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;在这里获取了map中的filedownloadUrl，并调用com.api.doc.detail.util.ImageConvertUtil#downloadUrl&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140367.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;如果上述配置是1的情况下&lt;br&gt;在com.api.doc.mobile.fileview.cmd.FileViewCmd#execute进入&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140368.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111140369.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;调用链路可能就短一点了。&lt;/p&gt;
&lt;h1 id=&quot;h1-u4FEEu590Du65B9u6848&quot;&gt;&lt;a name=&quot;修复方案&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;修复方案&lt;/h1&gt;&lt;p&gt;1、升级泛微版本&lt;/p&gt;
</description><pubDate>Thu, 11 Jul 2024 11:40:39 +0800</pubDate></item><item><title>&amp;quot;限时福利：Splashtop 免费送一年高级远程支持服务，价值990元&amp;quot;</title><link>https://uzzju.com/post/84.java</link><description>&lt;p&gt;我在22年记得发过一篇文章：&lt;a href=&quot;https://uzzju.com/post/76.java&quot; title=&quot;ipad远程MacBookPro远程办公的终极解决方案&quot;&gt;ipad远程MacBookPro远程办公的终极解决方案&lt;/a&gt;，在文章中我大致对比了不同远程软件在Ipad远程MacBookPro时，是否能够完全支持触控板，秒控键盘之间的支持与兼容。&lt;/p&gt;
&lt;p&gt;在当时&lt;a href=&quot;https://www.splashtop.cn/&quot; title=&quot;Splashtop&quot;&gt;Splashtop&lt;/a&gt;这款远程软件，无疑是在此场景下最适配与兼容最完美的软件，现在也是24年了，陆陆续续我也用了这款软件2年了，目前来看，相较于Todesk，向日葵，M1 Mac的客户端总是闪退错误，&lt;a href=&quot;https://www.splashtop.cn/&quot; title=&quot;Splashtop&quot;&gt;Splashtop&lt;/a&gt;在Mac和Windows相互远程上，确实做到的最好的兼容性。&lt;/p&gt;
&lt;p&gt;现在&lt;a href=&quot;https://www.splashtop.cn/&quot; title=&quot;Splashtop&quot;&gt;Splashtop&lt;/a&gt;这款远程软件现在免费赠送一年&lt;a href=&quot;https://www.splashtop.cn/&quot; title=&quot;专业商业远程支持软件&quot;&gt;专业商业远程支持软件&lt;/a&gt;「Splashtop SOS」，价值990元！没有套路，没有任何前置条件，直接送！&lt;/p&gt;
&lt;p&gt;领取方式：微信搜索「splashtopcn」，关注「Splashtop服务号」，回复「免费SOS+账户」，&lt;a href=&quot;https://www.splashtop.cn/&quot; title=&quot;Splashtop&quot;&gt;Splashtop&lt;/a&gt; 就会送你一年 SOS 软件。&lt;/p&gt;
&lt;p&gt;还没注册账户的，访问官网 &lt;a href=&quot;https://my.splashtop.com/signup&quot;&gt;https://my.splashtop.com/signup&lt;/a&gt; 可以快速注册。&lt;/p&gt;
&lt;p&gt;Splashtop SOS 无需安装，即下即用，通过一个9位连接码即可快速连接远端设备。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407082303213.gif&quot; alt=&quot;Splashtop SOS 连接方式&quot;&gt;&lt;br&gt;作为一款商业版远程支持软件，Splashtop SOS 拥有如下专业功能，你可以在使用过程中继续探索。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407111623843.png&quot; alt=&quot;SOS远程支持软件功能&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;h2-splashtop-&quot;&gt;&lt;a name=&quot;Splashtop 更多商业版软件&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;Splashtop 更多商业版软件&lt;/h2&gt;&lt;p&gt;除了 SOS，针对不同应用场景，Splashtop 还有几款强大的商业版远程软件。&lt;/p&gt;
&lt;h3 id=&quot;h3-splashtop-business-access&quot;&gt;&lt;a name=&quot;Splashtop Business Access&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;Splashtop Business Access&lt;/h3&gt;&lt;p&gt;一款高性能远程桌面控制软件，适合需要长期稳定远程连接的公司或个人使用。&lt;/p&gt;
&lt;p&gt;Splashtop Business Access 属于无人值守的远程控制软件，一般用来远程操控自己的设备，适合远程办公等场合。Splashtop SOS 属于有人值守的远程支持软件，一般用于远程支持和协助他人，被控端有人值守。这是两者的区别。&lt;/p&gt;
&lt;h3 id=&quot;h3-splashtop-enterprise&quot;&gt;&lt;a name=&quot;Splashtop Enterprise&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;Splashtop Enterprise&lt;/h3&gt;&lt;p&gt;为大型企业的 IT 运维、托管服务供应商（MSP）提供远程运维能力。在提供远程桌面访问能力之外，也包含终端管理能力，例如操作系统更新管理、系统安全管理、系统日志汇总、资产管理等功能。&lt;/p&gt;
&lt;h3 id=&quot;h3-splashtop-on-prem&quot;&gt;&lt;a name=&quot;Splashtop On-Prem&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;Splashtop On-Prem&lt;/h3&gt;&lt;p&gt;Splashtop On-Prem 是 Splashtop Enterprise 的本地部署版本，可以完全自托管在企业网络内部，提供集中式数据库和网页管理控制台。通过本地化部署，企业可以将 Splashtop On-Prem 部署在企业内部或云平台上，所有用户数据都保留在企业内部。&lt;/p&gt;
&lt;p&gt;如有需要，可以访问官网「splashtop.cn」了解和免费体验上述产品。&lt;/p&gt;
&lt;h2 id=&quot;h2-splashtop-&quot;&gt;&lt;a name=&quot;Splashtop 软件特性&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;Splashtop 软件特性&lt;/h2&gt;&lt;h3 id=&quot;h3-1-&quot;&gt;&lt;a name=&quot;1、高性能 高画质&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、高性能 高画质&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407082303115.gif&quot; alt=&quot;Splashtop Business Access 远程桌面控制工具&quot;&gt;&lt;br&gt;Splashtop 一直以高性能赢得客户口碑，支持 4K 分辨率、60 FPS 帧率，延迟很低，可以带来媲美真机的沉浸式远程访问体验。特别适合需要高分辨率图形和流畅画面的行业，比如影视、动画和建筑设计。&lt;/p&gt;
&lt;h3 id=&quot;h3-2-&quot;&gt;&lt;a name=&quot;2、全平台支持&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、全平台支持&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407082303279.png&quot; alt=&quot;Splashtop 支持操作系统&quot;&gt;&lt;br&gt;Splashtop 拥有广泛的设备支持，你几乎可以使用任意智能设备进行远程连接，支持 Windows、Mac、Linux、iOS、Android 等主流平台。&lt;/p&gt;
&lt;h3 id=&quot;h3-3-&quot;&gt;&lt;a name=&quot;3、安全可靠&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、安全可靠&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407082303045.png&quot; alt=&quot;Splashtop 安全性&quot;&gt;&lt;br&gt;Splashtop 一直投入大量技术资源来提高软件安全性，提供了包括：双因素认证、黑屏、空闲会话超时、远程连接通知、会话审计记录等众多安全功能。软件至今已安全运行 19 年，从未爆出安全漏洞。&lt;/p&gt;
&lt;p&gt;Splashtop 始终将软件安全和用户隐私放在首位，所有的远程会话均受 TLS 和 256 位 AES 加密技术保护。软件符合 GDPR、SOC2、FERPA 等主要的安全合规性要求，能够保护所有用户信息安全并保持数据的机密性、完整性和可用性。&lt;/p&gt;
&lt;h3 id=&quot;h3-4-&quot;&gt;&lt;a name=&quot;4、功能全面&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4、功能全面&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407082303959.gif&quot; alt=&quot;Splashtop Business Access 远程桌面控制软件&quot;&gt;&lt;br&gt;Splashtop 软件具备完善的专业功能，如文件传输、远程打印，团队管理、多显示器支持、聊天、共享屏幕、远程重启、会话录制等，全方位满足你的功能需求。还有更专业的远程触控笔、USB 设备重定向、麦克风直通、超高质量音频、4:4:4 色彩等功能，尤其适合建筑、设计、影视后期等行业。&lt;/p&gt;
&lt;h2 id=&quot;h2-splashtop-&quot;&gt;&lt;a name=&quot;Splashtop 简介&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;Splashtop 简介&lt;/h2&gt;&lt;p&gt;Splashtop Inc. 成立于 2006 年，总部位于硅谷，在杭州、台北、东京、新加坡、阿姆斯特丹等地设有分支机构。&lt;/p&gt;
&lt;p&gt;19 年来，Splashtop 产品一直安全稳定运营，以良好的产品和服务受到全球 3000 万用户、25万企业的信赖，包括 85% 的世界 500 强企业。2024 年，Splashtop 公司以 71 亿人民币的企业估值入选《2024·胡润全球独角兽榜》。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202407082303448.png&quot; alt=&quot;Splashtop 客户信赖&quot;&gt;&lt;/p&gt;
</description><pubDate>Mon, 08 Jul 2024 23:02:34 +0800</pubDate></item><item><title>未授权与垂直/水平越权(IDOR)检测实现方案</title><link>https://uzzju.com/post/83.java</link><description>&lt;h1 id=&quot;h1--idor-&quot;&gt;&lt;a name=&quot;未授权与垂直/水平越权(IDOR)检测实现方案&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;未授权与垂直/水平越权(IDOR)检测实现方案&lt;/h1&gt;&lt;h1 id=&quot;h1-todo&quot;&gt;&lt;a name=&quot;TODO&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;TODO&lt;/h1&gt;&lt;p&gt;1、去重通过接口进行去重&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;防止水平越权时参数不一致导致的同一个URL重复问题&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;2、黑名单配置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;让用户选择可以配置黑名单来禁止检测指定URL&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;3、白名单配置&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;让用户选择可以配置白名单来检测指定URL&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;检测host白名单配置，可以通过通配符的方式来匹配指定域名&lt;/p&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;4、多任务&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果同时存在多个任务如何处理，来区分不同任务所对应的cookie以及域名&lt;/li&gt;&lt;/ul&gt;
&lt;h1 id=&quot;h1--idor-&quot;&gt;&lt;a name=&quot;越权(IDOR)&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;越权(IDOR)&lt;/h1&gt;&lt;h2 id=&quot;h2-1-&quot;&gt;&lt;a name=&quot;1、越权漏洞与逻辑漏洞的边界&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、越权漏洞与逻辑漏洞的边界&lt;/h2&gt;&lt;p&gt;一直以来，非安全人员甚至安全人员都难以区分越权和逻辑漏洞的差异在哪，什么可以认定为越权漏洞，什么可以认定为是逻辑漏洞，我这里举几个例子，来详细介绍，如何理解越权与逻辑漏洞。&lt;/p&gt;
&lt;h3 id=&quot;h3-1-1-strong-strong-&quot;&gt;&lt;a name=&quot;1.1、&lt;strong&gt;首先什么是越权漏洞&lt;/strong&gt;&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.1、&lt;strong&gt;首先什么是越权漏洞&lt;/strong&gt;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;目前越权分为两种类型&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;水平越权&lt;/li&gt;&lt;li&gt;垂直越权&lt;/li&gt;&lt;/ul&gt;
&lt;h3 id=&quot;h3-1-2-&quot;&gt;&lt;a name=&quot;1.2、什么是垂直越权&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.2、什么是垂直越权&lt;/h3&gt;&lt;p&gt;其中垂直越权可以理解为，正常的业务流程是一个管理员拥有后台管理的所有权限，在这个后台中有用户鉴权体系，可以新增其他角色/权限的账号登录后台，分配对应的权限则拥有对应接口与页面的访问权限。&lt;/p&gt;
&lt;p&gt;例如后台功能如下&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;商户管理&lt;/li&gt;&lt;li&gt;订单管理&lt;/li&gt;&lt;li&gt;用户管理&lt;/li&gt;&lt;li&gt;日志审计&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;如果此时新建一个普通用户账号，只分配1个日志审计功能&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;账号：test&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;那么从业务角度上来说当前&lt;code&gt;test&lt;/code&gt;用户就只能拥有日志审计查看的权限，但是在大量的企业研发的案例中会发现，内部对于权限梳理上并没有做的非常细致，这就导致了，可能商户管理的某个接口，可以让&lt;code&gt;test&lt;/code&gt;用户访问到，此时就造成了垂直越权。&lt;/p&gt;
&lt;h3 id=&quot;h3-1-3-&quot;&gt;&lt;a name=&quot;1.3、什么是水平越权&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.3、什么是水平越权&lt;/h3&gt;&lt;p&gt;水平越权的理解上也比较容易，水平从字面理解是一个平面，水平线，那么代入到权限中是A与B用户拥有同一个权限，例如一个商城，A是一个用户，B也是一个用户，A在网站上购买一个口罩，订单的ID为：1（如果订单ID是递增的方式的话），那么B在网站上也购买一个口罩，订单ID为：2，那么此时如果B想通过查询订单的接口，试试把ID：2改为ID：1，是否可以查询到A账号的订单信息呢？&lt;/p&gt;
&lt;p&gt;如果此时查询成功，则代表，存在水平越权的漏洞。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;订单增删改查&lt;/li&gt;&lt;li&gt;地址增删改查&lt;/li&gt;&lt;li&gt;发票增删改查&lt;/li&gt;&lt;li&gt;等……&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281507376.png&quot; alt=&quot;业务逻辑越权之水平垂直越权&quot;&gt;&lt;/p&gt;
&lt;p&gt;从这张图上可以看到，垂直越权是从下至上的漏洞方式，作为一个普通用户，我无法访问的数据，没有权限的数据，我可以通过查找JS，Fuzz参数等方式查询到该接口的数据，即可以认定为存在垂直越权漏洞。&lt;/p&gt;
&lt;p&gt;那么水平越权则是从同一个权限获取到同一个权限的其他用户信息，则称为水平越权。&lt;/p&gt;
&lt;h3 id=&quot;h3-1-4-&quot;&gt;&lt;a name=&quot;1.4、什么是逻辑漏洞&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.4、什么是逻辑漏洞&lt;/h3&gt;&lt;p&gt;为什么我会认为逻辑漏洞可以与越权漏洞分开理解，原因如下：&lt;/p&gt;
&lt;p&gt;首先举一个例子，来看一下什么是逻辑漏洞&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以下取自火线众测后台漏洞案例&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;h4-1-4-1-strong-strong-&quot;&gt;&lt;a name=&quot;1.4.1、&lt;strong&gt;案例一&lt;/strong&gt;&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.4.1、&lt;strong&gt;案例一&lt;/strong&gt;&lt;/h4&gt;&lt;p&gt;快手APP上有一个通讯录获取好友的功能，通过该功能可以获取手机通讯录中有多少个好友正在使用快手APP，可以直接查询到账号，那么我们换一个角度来想，如果使用生成器，生成很多的手机号码，放入到通讯录中，再打开快手的APP，那么是否就已经反向知道对应的快手账户的手机号码是多少了呢？&lt;/p&gt;
&lt;h4 id=&quot;h4-1-4-2-strong-strong-&quot;&gt;&lt;a name=&quot;1.4.2、&lt;strong&gt;案例二&lt;/strong&gt;&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.4.2、&lt;strong&gt;案例二&lt;/strong&gt;&lt;/h4&gt;&lt;p&gt;现在使用Keep购买一个健身用品，例如一个手环，需要支付200元，但是购买健身用品的同时会赠送一些赠品，例如赠送蜡烛，毛巾等，那么每一个商品都会存在SKUid，那么此时就可能会存在一个问题，我首先将手环加入到购物车，在购物车正常选择赠品，例如现在选择一个蜡烛，随后点击提交的时候，将蜡烛的SKUID替换为一个价值1000元的手表的SKUID，如果存在逻辑漏洞，是否就下单购买成功，只需要支付200元就可以获得1个手环和1个价值1000元的手表。&lt;/p&gt;
&lt;h4 id=&quot;h4-1-4-3-strong-strong-&quot;&gt;&lt;a name=&quot;1.4.3、&lt;strong&gt;案例三&lt;/strong&gt;&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.4.3、&lt;strong&gt;案例三&lt;/strong&gt;&lt;/h4&gt;&lt;p&gt;任意用户注册的逻辑场景，现在正常走注册的逻辑流程，输入账号，密码，手机号，但是我希望使用别人的手机号码进行注册，但是我又无法知道验证码是什么，那么此时提交错误的验证码，收到的返回肯定是验证码不正确，但是如果修改响应包呢？&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281525583.png&quot; alt=&quot;image-20230328152553546&quot;&gt;&lt;/p&gt;
&lt;p&gt;例如上图，将success和code都修改成0和true，那么此时可能会跳过验证码校验，让前端的UI进入到下一步&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281526524.png&quot; alt=&quot;image-20230328152639488&quot;&gt;&lt;/p&gt;
&lt;p&gt;那么此时设置登录的账号，昵称，设置密码，确认密码，点击下一步应该就是注册成功&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281527981.png&quot; alt=&quot;image-20230328152717947&quot;&gt;&lt;/p&gt;
&lt;p&gt;随后发现账号是可以正常登录成功的，那么此时考虑一个问题，这里到底是手机验证码验证的接口出现了问题，还是注册接口出现了问题？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正常的业务逻辑&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281528562.png&quot; alt=&quot;image-20230328152850532&quot;&gt;&lt;/p&gt;
&lt;p&gt;上面的这张图中间其实应该加一个校验，应该如下才是对的&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里其实会存在一个问题，那么也就是如果有人强制修改响应包来修改前端跳转的逻辑的话，如果没有做校验，也会存在问题，比如发送了验证码之后，我输入123456，随后修改这个请求的响应包，将返回的False修改为True，那么也能来到下面的注册逻辑&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281529907.png&quot; alt=&quot;image-20230328152913877&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;存在漏洞的业务逻辑&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281529929.png&quot; alt=&quot;image-20230328152925883&quot;&gt;&lt;/p&gt;
&lt;p&gt;其实除了上述验证码爆破，修改响应包后走下一步逻辑并且注册接口并未校验验证码这两个问题之外，还有一个比较少见的逻辑问题&lt;/p&gt;
&lt;p&gt;1、先正常走一遍业务登录注册逻辑&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1、输入正确验证码&lt;/li&gt;&lt;li&gt;2、服务端校验后返回Token/成功的参数(遇到过输入正确验证码之后返回一段Token，并在注册的时候会带上这个token)，把这里的响应包复制下来（这里称为正确的响应包）&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;2、走恶意的业务登录注册逻辑&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1、输入错误验证码&lt;ul&gt;
&lt;li&gt;2、拦截响应包（这里的响应包称为错误的响应包)&lt;ul&gt;
&lt;li&gt;3、将正确业务逻辑的响应包的token或者整个正确的响应包替换这个错误的响应包&lt;ul&gt;
&lt;li&gt;4、随后继续走业务注册逻辑，也会注册成功&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;上述的这个逻辑问题，我认为本质就把这里的token当做一个令牌了，服务端不在乎是谁申请的这个令牌，只校验了谁有这个令牌，这个令牌是否有效，如果有效就通过即可，最终就会导致问题。&lt;br&gt;那么哈罗这里的根本原因是，/merchant/register/registerAccount这个接口未对验证码进行校验，&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;因为拿软件暴力破解举一个例子，在软件启动时会提示用户是否注册，如果没有就无法使用，那么可以直接将汇编代码中的JNZ等判断修改为强制的JMP，这样如果没有其他校验，就可以正常使用软件功能&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里的本质问题还是开发者无法防止用户去修改一些前端显示逻辑，但是可以在注册接口（也就是/merchant/register/registerAccount进行校验）这样哪怕用户强制修改前端逻辑，甚至在JS中fuzz或直接构造参数请求该接口，都会提示验证码错误，无法注册。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tips: 这里需要注意的是，开发者不仅仅只是校验验证码是否有效，因为如果只校验验证码是否有效的话，那么我随便用一个手机号码发一个有效的验证码都可以使用，这样是不行的，应该还需要判断，该验证码是否属于该手机号码，并且是否有效（这里可能会说，例如腾讯 百度这种用户基数特别大的，是否会出现验证码重复的概念呢？大概率是会的，不过验证码使用后失效即可）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;h2-2-&quot;&gt;&lt;a name=&quot;2、垂直/水平越权漏洞产生的主要原因与场景&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、垂直/水平越权漏洞产生的主要原因与场景&lt;/h2&gt;&lt;h3 id=&quot;h3-2-1-&quot;&gt;&lt;a name=&quot;2.1、垂直/水平越权漏洞产生的主要原因&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.1、垂直/水平越权漏洞产生的主要原因&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;比较通用的说法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;通常情况下，一个 Web 程序功能流程是登录 - 提交请求 - 验证权限 - 数据库查询 - 返回结果。如果验证权限不足，便会导致越权。常见的程序都会认为通过登录后即可验证用户的身份，从而不会做下一步验证，最后导致越权。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1、通过隐藏 URL&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实现控制访问有些程序的管理员的管理页面只有管理员才显示，普通用户看不到，利用 URL 实现访问控制，但 URL 泄露或被恶意攻击者猜到后，这会导致越权攻击。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2、直接对象引用&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这种通过修改一下参数就可以产生水平越权，例如查看用户信息页面 URL 后加上自己的 id 便可查看，当修改为他人的 ID 号时会返回他人的信息，便产生了水平越权。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3、多阶段功能&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多阶段功能是一个功能有多个阶段的实现。例如修改密码，可能第一步是验证用户身份信息，号码验证码类的。当验证成功后，跳到第二步，输入新密码，很多程序会在这一步不再验证用户身份，导致恶意攻击者抓包直接修改参数值，导致可修改任意用户密码。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4、静态文件&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;很多网站的下载功能，一些被下载的静态文件，例如 pdf、word、xls 等，可能只有付费用户或会员可下载，但当这些文件的 URL 地址泄露后，导致任何人可下载，如果知道 URL 命名规则，则会便利服务器的收费文档进行批量下载。&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;5、平台配置错误&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一些程序会通过控件来限制用户的访问，例如后台地址，普通用户不属于管理员组，则不能访问。但当配置平台或配置控件错误时，就会出现越权访问。&lt;/li&gt;&lt;/ul&gt;
&lt;h3 id=&quot;h3-2-2-&quot;&gt;&lt;a name=&quot;2.2、会有哪些场景？&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.2、会有哪些场景？&lt;/h3&gt;&lt;h4 id=&quot;h4-2-2-1-&quot;&gt;&lt;a name=&quot;2.2.1、垂直越权&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.2.1、垂直越权&lt;/h4&gt;&lt;p&gt;垂直越权出现的位置，更多的在管理后台，并且管理后台有用户鉴权体系，特别是在同一个管理后台中还存在，商户，用户，管理员，多种用户的角色和关系，这类型的场景出现垂直越权的可能性是最大的。&lt;/p&gt;
&lt;h4 id=&quot;h4-2-2-2-&quot;&gt;&lt;a name=&quot;2.2.2、水平越权&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.2.2、水平越权&lt;/h4&gt;&lt;p&gt;水平越权出现的位置相对来说比较普遍，例如一个商城，购物APP，发票网站等等，在订单，地址，发票，用户信息，收藏店家，删除订单等位置是最容易出现水平越权的地方，并且很多研发写代码比如一个订单号，是使用一个可递增遍历的数字来表示订单，例如订单ID为1,2,3,4,5以此类推，那么如果此时遍历这个订单ID，就有可能获取到其他用户的订单信息。&lt;/p&gt;
&lt;h2 id=&quot;h2-3-&quot;&gt;&lt;a name=&quot;3、越权漏洞检测实现的难点&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、越权漏洞检测实现的难点&lt;/h2&gt;&lt;p&gt;目前这个版本的越权和未授权检测是我重构之后的（代码工程能力不强），早些的一个版本也是使用mitmproxy来实现的HTTP/S的监听，但是发现，mitmproxy使用&lt;code&gt;addons = [CaptureInfoWriteFile()]&lt;/code&gt;的方式来实现&lt;code&gt;request&lt;/code&gt;和&lt;code&gt;response&lt;/code&gt;有一个问题是会出现阻塞的情况，特别是越权需要去解析一个HTTP/S请求，然后替换token请求的，那么此时在替换token请求这一步操作上很容易发生阻塞的情况，导致正常的功能测试页面一直无法返回。&lt;/p&gt;
&lt;p&gt;当前重构的版本，采用&lt;code&gt;asyncio&lt;/code&gt;异步的方式来实现的异步，每一次都会新增一个异步线程任务，使用后会清除当前线程任务。&lt;/p&gt;
&lt;p&gt;目前主要实现的难点有以下几项&lt;/p&gt;
&lt;p&gt;1、垂直越权&lt;/p&gt;
&lt;p&gt;垂直越权的实现相对简单很多，只需要将原始请求与修改后的请求的响应包进行差异值比较即可&lt;/p&gt;
&lt;p&gt;但是也无法避免&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果接口对于用户鉴权体系来说是公共的如何识别？&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;2、水平越权&lt;/p&gt;
&lt;p&gt;水平越权的实现相对就比较难，可以使用替换两个权限相同的token来进行差异值的比较，但是如果接口是&lt;/p&gt;
&lt;p&gt;目前主要实现&lt;/p&gt;
&lt;p&gt;1、如何解决参数识别问题  （已解决）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RESFUL HTTP参数识别（已解决）&lt;br&gt;2、如何解决规则库，使用什么解决方法来让保证规则库的通用性和可扩展性&lt;br&gt;3、如何自动化识别不同的权限校验头  （已解决）&lt;br&gt;4、如何解决参数加密场景的问题  &lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;6、是否要采用数据持久化方案 使用sqlit or mysql or mongodb or redis&lt;br&gt;7、不同请求替换参数 Cookie后请求响应如何判断差异性，如余弦相似度判断，相似度应该控制在多少合适？是否有更好的算法解决该问题&lt;br&gt;8、自动化登录 防止cookie失效&lt;/p&gt;
&lt;h2 id=&quot;h2-4-&quot;&gt;&lt;a name=&quot;4、如何使用现有的方案来实现越权检测&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4、如何使用现有的方案来实现越权检测&lt;/h2&gt;&lt;h3 id=&quot;h3-4-1-&quot;&gt;&lt;a name=&quot;4.1、余弦相似度判断差异性&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.1、余弦相似度判断差异性&lt;/h3&gt;&lt;p&gt; &lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281554404.png&quot; alt=&quot;image-20230328155457367&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;h2-5-&quot;&gt;&lt;a name=&quot;5、实践落地&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5、实践落地&lt;/h2&gt;&lt;p&gt;针对所有的场景包括代码的编写，都是针对真实场景进行编写，不涉及靶场。&lt;/p&gt;
&lt;h3 id=&quot;h3-5-1-&quot;&gt;&lt;a name=&quot;5.1、拉卡拉&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.1、拉卡拉&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303281558095.png&quot; alt=&quot;image-20230328155826059&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;h3-5-2-&quot;&gt;&lt;a name=&quot;5.2、享道出行&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.2、享道出行&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303301728797.jpg&quot; alt=&quot;img_v2_c68fba15-786c-4371-9e44-dd4e73aedb1g&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303301728515.jpg&quot; alt=&quot;img_v2_878ad6ba-d658-4fd2-9abd-3fb4d83ea69g&quot;&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303301728425.jpg&quot; alt=&quot;img_v2_ccd5f023-6288-4f53-98c6-608cf1b6010g&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;h3-5-3-src&quot;&gt;&lt;a name=&quot;5.3、字节SRC&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.3、字节SRC&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202304111429132.png&quot; alt=&quot;image-20230411142909990&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;h3-5-4-&quot;&gt;&lt;a name=&quot;5.4、自如&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.4、自如&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://i0x0fy4ibf.feishu.cn/wiki/wikcnz28wEH6ifNAsD7CVSO0Atd&quot;&gt;https://i0x0fy4ibf.feishu.cn/wiki/wikcnz28wEH6ifNAsD7CVSO0Atd&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;h1-u672Au6388u6743u8BBFu95EE&quot;&gt;&lt;a name=&quot;未授权访问&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;未授权访问&lt;/h1&gt;&lt;h2 id=&quot;h2-1-&quot;&gt;&lt;a name=&quot;1、为什么会出现未授权&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、为什么会出现未授权&lt;/h2&gt;&lt;p&gt;未授权的场景可以理解为：访问一个接口，将cookie/token删除，重新请求接口如果还是存在数据返回，则存在未授权访问。&lt;/p&gt;
&lt;p&gt;但是未授权又分三个场景&lt;/p&gt;
&lt;p&gt;1、后端没有对请求的cookie/token进行校验就走了业务逻辑流程导致返回了数据&lt;/p&gt;
&lt;p&gt;2、后端判断了当前请求是否带有cookie/token，但是没有判断当前token/cookie是否有效&lt;/p&gt;
&lt;p&gt;3、后端判断了当前请求是否带有cookie/token，但是没有判断当前的token/cookie是否有权限访问这个数据&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里有点像越权的范畴，需要清晰了解未授权与越权漏洞的边界&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;h2-2-&quot;&gt;&lt;a name=&quot;2、未授权检测实现方案&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、未授权检测实现方案&lt;/h2&gt;&lt;p&gt;例如这是一个正常请求头&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;Headers[(b&amp;#39;Host&amp;#39;, b&amp;#39;172.20.10.5:8109&amp;#39;), (b&amp;#39;User-Agent&amp;#39;, b&amp;#39;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/111.0&amp;#39;), (b&amp;#39;Accept&amp;#39;, b&amp;#39;*/*&amp;#39;), (b&amp;#39;Accept-Language&amp;#39;, b&amp;#39;zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2&amp;#39;), (b&amp;#39;Accept-Encoding&amp;#39;, b&amp;#39;gzip, deflate&amp;#39;), (b&amp;#39;Connection&amp;#39;, b&amp;#39;keep-alive&amp;#39;), (b&amp;#39;Cookie&amp;#39;, b&amp;#39;session=eyJ1c2VyaWQiOjI3LCJ1c2Vycm9sZWlkIjo5OX0.ZCQjlw.IqMSJjOnlony_c1gtf18URKrGMU&amp;#39;)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时存在cookie这个键值对，如果此时将cookie删除&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;[(b&amp;#39;Host&amp;#39;, b&amp;#39;172.20.10.5:8109&amp;#39;), (b&amp;#39;User-Agent&amp;#39;, b&amp;#39;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/111.0&amp;#39;), (b&amp;#39;Accept&amp;#39;, b&amp;#39;*/*&amp;#39;), (b&amp;#39;Accept-Language&amp;#39;, b&amp;#39;zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2&amp;#39;), (b&amp;#39;Accept-Encoding&amp;#39;, b&amp;#39;gzip, deflate&amp;#39;), (b&amp;#39;X-Requested-With&amp;#39;, b&amp;#39;XMLHttpRequest&amp;#39;), (b&amp;#39;Connection&amp;#39;, b&amp;#39;keep-alive&amp;#39;), (b&amp;#39;Referer&amp;#39;, b&amp;#39;http://172.20.10.5:8109/usermanager&amp;#39;)]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202303291945638.png&quot; alt=&quot;image-20230329194540540&quot;&gt;&lt;/p&gt;
&lt;p&gt;通过计算返回值的余弦相似度就可以获得想要的结果。&lt;/p&gt;
&lt;h1 id=&quot;h1-u8D8Au6743u5B9Eu73B0u65B9u6848u4E8C&quot;&gt;&lt;a name=&quot;越权实现方案二&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;越权实现方案二&lt;/h1&gt;&lt;p&gt;上述方案存在部分缺点&lt;/p&gt;
&lt;p&gt;1、需要用户配置代理&lt;/p&gt;
&lt;p&gt;2、需要用户手动配置账号token&lt;/p&gt;
&lt;p&gt;这在甲方安全建设推动中会极大的影响效率以及安全部门推进的速度。&lt;/p&gt;
&lt;p&gt;实现方案二主要解决了上述2个问题。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202308091616998&quot; alt=&quot;img&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;h2-1-golang-gopacket-&quot;&gt;&lt;a name=&quot;1、GoLang gopacket实现&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、GoLang gopacket实现&lt;/h2&gt;&lt;h3 id=&quot;h3-1-1-&quot;&gt;&lt;a name=&quot;1.1、实现方式一&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.1、实现方式一&lt;/h3&gt;&lt;h4 id=&quot;h4-1-1-http-&quot;&gt;&lt;a name=&quot;1.1、获取HTTP请求&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.1、获取HTTP请求&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package main

import (
    &amp;quot;fmt&amp;quot;
    &amp;quot;github.com/google/gopacket&amp;quot;
    &amp;quot;github.com/google/gopacket/layers&amp;quot;
    &amp;quot;github.com/google/gopacket/pcap&amp;quot;
    &amp;quot;log&amp;quot;
    &amp;quot;time&amp;quot;
)

func main() {
    const (
        // 网络设备
        EthDev string = &amp;quot;eth0&amp;quot;
        // 抓取数据长度
        SnapLen int32 = 65535
        // 是否开启混合模式，混合模式就是不属于本网卡IP的流量
        Promisc bool = false
        // 展示细节的时间
        Timeout time.Duration = time.Second * 3
        // 抓取端口
        DstPort layers.TCPPort = 8088
    )
    // 对网卡流量进行实时捕获
    handler, err := pcap.OpenLive(EthDev, SnapLen, Promisc, Timeout)
    if err != nil {
        log.Fatalln(err)
    }
    defer handler.Close()
    // 获取包源
    source := gopacket.NewPacketSource(handler, handler.LinkType())
    var isApp bool
    for pk := range source.Packets() {
        // 网络四层模型
        // LinkLayer returns the first link layer in the packet
        // LinkLayer() LinkLayer
        // NetworkLayer returns the first network layer in the packet
        // NetworkLayer() NetworkLayer
        // TransportLayer returns the first transport layer in the packet
        // TransportLayer() TransportLayer
        // ApplicationLayer returns the first application layer in the packet
        // ApplicationLayer() ApplicationLayer

        isApp = false
        if layer := pk.TransportLayer(); layer != nil {
            if tcpLayer, ok := layer.(*layers.TCP); ok &amp;amp;&amp;amp; tcpLayer.DstPort == DstPort {
                fmt.Println()
                fmt.Printf(&amp;quot;TCP Payload: %s\n&amp;quot;, string(tcpLayer.Payload))
                fmt.Printf(&amp;quot;TCP ContentsLenght: %d \n&amp;quot;, len(tcpLayer.Contents))
                fmt.Println(pk.String())
                if len(tcpLayer.Payload) &amp;gt; 0 {
                    isApp = true
                }
            }
        }

        if isApp {
            if appLayer := pk.ApplicationLayer(); appLayer != nil {
                fmt.Println(&amp;quot;APP Contents:&amp;quot;, string(appLayer.LayerContents()))
                fmt.Println(&amp;quot;APP Contents Length:&amp;quot;, len(appLayer.LayerContents()))
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;基础实现Demo如上代码示例&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202308101200333.png&quot; alt=&quot;image-20230810120023250&quot;&gt;&lt;/p&gt;
&lt;p&gt;可以获取HTTP请求&lt;/p&gt;
&lt;h4 id=&quot;h4-1-2-https-&quot;&gt;&lt;a name=&quot;1.2、获取HTTPS请求&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.2、获取HTTPS请求&lt;/h4&gt;&lt;p&gt;暂时没找到实现HTTPS的方案&lt;/p&gt;
&lt;h3 id=&quot;h3-1-2-&quot;&gt;&lt;a name=&quot;1.2、实现方式二&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.2、实现方式二&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package main

import (
    &amp;quot;fmt&amp;quot;
    &amp;quot;log&amp;quot;
    &amp;quot;os&amp;quot;
    &amp;quot;os/signal&amp;quot;
    &amp;quot;strings&amp;quot;
    &amp;quot;syscall&amp;quot;

    &amp;quot;github.com/google/gopacket&amp;quot;
    &amp;quot;github.com/google/gopacket/pcap&amp;quot;
)

func main() {
    handle, err := pcap.OpenLive(&amp;quot;any&amp;quot;, 1600, true, pcap.BlockForever)
    if err != nil {
        log.Fatal(err)
    }
    defer handle.Close()

    filter := &amp;quot;tcp&amp;quot;
    if err := handle.SetBPFFilter(filter); err != nil {
        log.Fatal(err)
    }

    packetSource := gopacket.NewPacketSource(handle, handle.LinkType())

    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

    fmt.Println(&amp;quot;Starting packet capture...&amp;quot;)
    for {
        select {
        case packet := &amp;lt;-packetSource.Packets():
            // 检查数据包是否是HTTP请求
            if appLayer := packet.ApplicationLayer(); appLayer != nil {
                payload := appLayer.Payload()
                if bytesContain(payload, []byte(&amp;quot;HTTP&amp;quot;)) {
                    // 解析HTTP请求的Header
                    headers := parseHTTPHeaders(payload)
                    fmt.Println(&amp;quot;=== HTTP Request Headers ===&amp;quot;)
                    for name, value := range headers {
                        fmt.Printf(&amp;quot;%s : %s\n&amp;quot;, name, value)
                    }
                    fmt.Println(&amp;quot;=============================&amp;quot;)
                }
            }
        case &amp;lt;-sigChan:
            fmt.Println(&amp;quot;Stopping packet capture...&amp;quot;)
            return
        }
    }
}

func bytesContain(source, target []byte) bool {
    for i := 0; i &amp;lt;= len(source)-len(target); i++ {
        if bytesEqual(source[i:i+len(target)], target) {
            return true
        }
    }
    return false
}

func bytesEqual(a, b []byte) bool {
    if len(a) != len(b) {
        return false
    }
    for i, v := range a {
        if v != b[i] {
            return false
        }
    }
    return true
}

func parseHTTPHeaders(payload []byte) map[string]string {
    headers := make(map[string]string)
    lines := strings.Split(string(payload), &amp;quot;\r\n&amp;quot;)
    for _, line := range lines {
        parts := strings.SplitN(line, &amp;quot;: &amp;quot;, 2)
        if len(parts) == 2 {
            headers[parts[0]] = parts[1]
        }
    }
    return headers
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该实现放在调用pcap.OpenLive的时候传入了any表示所有的网卡流量都采集，并且在fillter只选择TCP，也就最后是HTTP的流量。&lt;/p&gt;
&lt;h2 id=&quot;h2-2-python-scapy-&quot;&gt;&lt;a name=&quot;2、Python Scapy实现&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、Python Scapy实现&lt;/h2&gt;&lt;h3 id=&quot;h3-2-1-&quot;&gt;&lt;a name=&quot;2.1、实现方式一&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.1、实现方式一&lt;/h3&gt;&lt;p&gt;该实现方式可以让用户准确配置，采集的端口和网卡&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;# -*- coding: utf-8 -*-
# @Time    : 2023/8/11 10:17
# @Author  : UzJu
# @Site    : UzzJu.com
# @File    : py_snniffer.py
# @Software: PyCharm 
# @Comment : :)
# ! /usr/bin/env python3
from scapy.all import *


def http_header(packet):
    http_packet = str(packet)
    if &amp;quot;GET&amp;quot; in http_packet:
        return GET_print(packet)


def GET_print(packet1):
    ret = &amp;quot;***************************************GET PACKET****************************************************\n&amp;quot;
    ret += &amp;quot;\n&amp;quot;.join(packet1.sprintf(&amp;quot;{Raw:%Raw.load%}\n&amp;quot;).split(r&amp;quot;\r\n&amp;quot;))
    ret += &amp;quot;*****************************************************************************************************&amp;quot;
    print(ret)


def main():
    sniff(iface=&amp;quot;en0&amp;quot;, prn=http_header, filter=&amp;quot;tcp port 6234&amp;quot;)


if __name__ == &amp;#39;__main__&amp;#39;:
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202308111102156.png&quot; alt=&quot;image-20230811110205083&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;h3-2-2-&quot;&gt;&lt;a name=&quot;2.2、实现方式二&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.2、实现方式二&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from scapy.all import *


def process_packet(packet):
    if packet.haslayer(TCP) and packet.haslayer(Raw):
        payload = packet[Raw].load.decode(&amp;#39;utf-8&amp;#39;, errors=&amp;#39;ignore&amp;#39;)
        if &amp;#39;HTTP&amp;#39; in payload:
            http_headers = payload.split(&amp;#39;\r\n\r\n&amp;#39;)[0].split(&amp;#39;\r\n&amp;#39;)[1:]
            print(&amp;quot;=== HTTP Request Headers ===&amp;quot;)
            for header in http_headers:
                print(header)


def main():
    sniff(filter=&amp;#39;tcp&amp;#39;, prn=process_packet, store=0)


if __name__ == &amp;quot;__main__&amp;quot;:
    main()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种实现方式，只采集HTTP流量，并且输出，也就意味着会无差别的采集服务器上所有端口的HTTP流量(不包含HTTPS)。&lt;/p&gt;
&lt;p&gt;相较于实现方式一的好处是用户无需配置，安装agent即可。&lt;/p&gt;
&lt;h2 id=&quot;h2-3-&quot;&gt;&lt;a name=&quot;3、具体实现&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、具体实现&lt;/h2&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package main

import (
    &amp;quot;encoding/json&amp;quot;
    &amp;quot;fmt&amp;quot;
    &amp;quot;log&amp;quot;
    &amp;quot;os&amp;quot;
    &amp;quot;os/signal&amp;quot;
    &amp;quot;strings&amp;quot;
    &amp;quot;syscall&amp;quot;

    &amp;quot;github.com/google/gopacket&amp;quot;
    &amp;quot;github.com/google/gopacket/pcap&amp;quot;
)

type RequestHttpHeaders struct {
    Method  string
    URL     string
    Headers map[string]string
    Body    string
}

type ResponseHttpHeaders struct {
    Headers map[string]string
    Body    string
}

type HTTPRequestResponse struct {
    Request  HTTPHeaders `json:&amp;quot;request&amp;quot;`
    Response HTTPHeaders `json:&amp;quot;response&amp;quot;`
}

type HTTPHeaders struct {
    Method    string            `json:&amp;quot;method&amp;quot;`
    URL       string            `json:&amp;quot;url&amp;quot;`
    Headers   map[string]string `json:&amp;quot;headers&amp;quot;`
    Body      string            `json:&amp;quot;body&amp;quot;`
    IsRequest bool              `json:&amp;quot;-&amp;quot;`
}

func main() {
    handle, err := pcap.OpenLive(&amp;quot;any&amp;quot;, 65535, true, pcap.BlockForever)
    if err != nil {
        log.Fatal(err)
    }
    defer handle.Close()

    filter := &amp;quot;tcp&amp;quot;
    if err := handle.SetBPFFilter(filter); err != nil {
        log.Fatal(err)
    }

    packetSource := gopacket.NewPacketSource(handle, handle.LinkType())

    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

    var requestsResponses []HTTPRequestResponse

    fmt.Println(&amp;quot;Starting packet capture...&amp;quot;)
    for {
        select {
        case packet := &amp;lt;-packetSource.Packets():
            if appLayer := packet.ApplicationLayer(); appLayer != nil {
                payload := appLayer.Payload()
                if bytesContain(payload, []byte(&amp;quot;HTTP&amp;quot;)) {
                    headers, body := parseHTTPHeaderAndBody(payload)
                    isRequest := strings.Contains(string(payload), &amp;quot;GET&amp;quot;) || strings.Contains(string(payload), &amp;quot;POST&amp;quot;)

                    httpHeaders := HTTPHeaders{
                        Method:    getRequestMethod(payload),
                        URL:       getRequestURL(payload),
                        Headers:   headers,
                        Body:      body,
                        IsRequest: isRequest,
                    }

                    if isRequest {
                        requestsResponses = append(requestsResponses, HTTPRequestResponse{
                            Request:  httpHeaders,
                            Response: HTTPHeaders{},
                        })
                    } else {
                        lastIdx := len(requestsResponses) - 1
                        if lastIdx &amp;gt;= 0 {
                            requestsResponses[lastIdx].Response = httpHeaders
                        }
                    }
                }
            }
        case &amp;lt;-sigChan:
            fmt.Println(&amp;quot;Stopping packet capture...&amp;quot;)

            data, err := json.MarshalIndent(requestsResponses, &amp;quot;&amp;quot;, &amp;quot;  &amp;quot;)
            if err != nil {
                log.Fatal(err)
            }
            if err := os.WriteFile(&amp;quot;requests_responses.json&amp;quot;, data, 0644); err != nil {
                log.Fatal(err)
            }

            return
        }
    }
}

func bytesContain(source, target []byte) bool {
    for i := 0; i &amp;lt;= len(source)-len(target); i++ {
        if bytesEqual(source[i:i+len(target)], target) {
            return true
        }
    }
    return false
}

func bytesEqual(a, b []byte) bool {
    if len(a) != len(b) {
        return false
    }
    for i, v := range a {
        if v != b[i] {
            return false
        }
    }
    return true
}

func parseHTTPHeaderAndBody(payload []byte) (map[string]string, string) {
    headers := make(map[string]string)
    lines := strings.Split(string(payload), &amp;quot;\r\n&amp;quot;)
    var body string
    for i, line := range lines {
        if line == &amp;quot;&amp;quot; {
            body = strings.Join(lines[i+1:], &amp;quot;\r\n&amp;quot;)
            break
        }
        parts := strings.SplitN(line, &amp;quot;: &amp;quot;, 2)
        if len(parts) == 2 {
            headers[parts[0]] = parts[1]
            if parts[0] == &amp;quot;Host&amp;quot; &amp;amp;&amp;amp; strings.HasPrefix(parts[1], &amp;quot;http&amp;quot;) {
                headers[&amp;quot;Method&amp;quot;] = strings.Fields(lines[i+1])[0]
                headers[&amp;quot;URL&amp;quot;] = parts[1]
            }
        }
    }
    return headers, body
}
func getRequestMethod(payload []byte) string {
    lines := strings.Split(string(payload), &amp;quot;\r\n&amp;quot;)
    parts := strings.Fields(lines[0])
    if len(parts) &amp;gt; 0 {
        return parts[0]
    }
    return &amp;quot;&amp;quot;
}

func getRequestURL(payload []byte) string {
    lines := strings.Split(string(payload), &amp;quot;\r\n&amp;quot;)
    parts := strings.Fields(lines[0])
    if len(parts) &amp;gt; 1 {
        return parts[1]
    }
    return &amp;quot;&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述代码主要功能，通过采集所有网卡(any)，最大65535字节大小的HTTP GET/POST请求，并给到结构体，最后输出到JSON文件中。&lt;/p&gt;
&lt;p&gt;采集的数据如下&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/test_file/requests_responses.json&quot;&gt;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/test_file/requests_responses.json&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202308141630042.png&quot; alt=&quot;image-20230814163015998&quot;&gt;&lt;/p&gt;
&lt;p&gt;从上面的流程中已经拿到了完整的HTTP请求，只需要传输到接口上，下面用flask简单实现一个接口&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from flask import Flask, request

app = Flask(__name__)


@app.route(&amp;#39;/receive&amp;#39;, methods=[&amp;#39;POST&amp;#39;])
def receive_json():
    json_data = request.json
    print(&amp;quot;Received JSON Data:&amp;quot;)
    print(json_data)
    return &amp;#39;JSON data received&amp;#39;


if __name__ == &amp;#39;__main__&amp;#39;:
    app.run(host=&amp;#39;0.0.0.0&amp;#39;, port=8888)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;获取JSON数据即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202308151042038.png&quot; alt=&quot;image-20230815104237937&quot;&gt;&lt;/p&gt;
&lt;p&gt;主要思路&lt;/p&gt;
&lt;p&gt;1、采集HTTP请求&lt;/p&gt;
&lt;p&gt;2、传输至服务端进行解析&lt;/p&gt;
&lt;p&gt;3、替换鉴权字段重新请求&lt;/p&gt;
&lt;p&gt;4、判断是否存在越权漏洞。&lt;/p&gt;
&lt;h2 id=&quot;h2-4-&quot;&gt;&lt;a name=&quot;4、上述方案的缺点&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4、上述方案的缺点&lt;/h2&gt;&lt;p&gt;1、无法采集HTTPS流量。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;https解决方案&lt;ul&gt;
&lt;li&gt;ebpf&lt;/li&gt;&lt;li&gt;代理装证书&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;2、gopacket无法采集到响应&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202308141521090.png&quot; alt=&quot;image-20230814152133018&quot;&gt;&lt;/p&gt;
&lt;p&gt;在测试中发现gopacket的嗅探采集是类似异步，不太好将request和response一一对应。&lt;/p&gt;
</description><pubDate>Fri, 13 Oct 2023 14:06:01 +0800</pubDate></item><item><title>洞态IAST检测优化：Fel表达式注入</title><link>https://uzzju.com/post/82.java</link><description>&lt;h1 id=&quot;h1--&quot;&gt;&lt;a name=&quot;一、简介&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;一、简介&lt;/h1&gt;&lt;p&gt;　Fel是开放的，引擎执行中的多个模块都可以扩展或替换。Fel的执行主要是通过函数实现,运算符(+、-等都是Fel函数），所有这些函数都是可以替换的，扩展函数也非常简单。&lt;/p&gt;
&lt;p&gt;   Fel有双引擎，同时支持解释执行和编译执行。可以根据性能要求选择执行方式。编译执行就是将表达式编译成字节码（生成java代码和编译模块都是可以扩展和替换的）&lt;/p&gt;
&lt;p&gt;　FEL可以进行算数运算以及逻辑运算，也可以调用类的静态方法、非静态方法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pom.xml&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.eweb4j&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;fel&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.8&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;老古董：&lt;a href=&quot;https://github.com/dbcxy/fast-el/tree/master&quot;&gt;https://github.com/dbcxy/fast-el/tree/master&lt;/a&gt;&lt;br&gt;Google Code：&lt;a href=&quot;https://code.google.com/archive/p/fast-el/&quot;&gt;https://code.google.com/archive/p/fast-el/&lt;/a&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202310091502554.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;h1--&quot;&gt;&lt;a name=&quot;二、友商测试&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;二、友商测试&lt;/h1&gt;&lt;h2 id=&quot;h2-1-&quot;&gt;&lt;a name=&quot;1、默安-无法检测&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、默安-无法检测&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202310091454812.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;h1--iast&quot;&gt;&lt;a name=&quot;三、洞态IAST&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;三、洞态IAST&lt;/h1&gt;&lt;h2 id=&quot;h2-1-&quot;&gt;&lt;a name=&quot;1、描述&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、描述&lt;/h2&gt;&lt;p&gt;el在源自于企业项目，设计目标是为了满足不断变化的功能需求和性能需求。&lt;br&gt;Fel是开放的，引擎执行中的多个模块都可以扩展或替换。Fel的执行主要是通过函数实现,运算符(+、-等都是Fel函数），所有这些函数都是可以替换的，扩展函数也非常简单。&lt;br&gt;Fel可以执行表达式，如果此时Fel执行的表达式外部可控，则可能导致安全风险。&lt;/p&gt;
&lt;h2 id=&quot;h2-2-&quot;&gt;&lt;a name=&quot;2、检测规则&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、检测规则&lt;/h2&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;com.greenpineyu.fel.parser.AntlrParser.parse(java.lang.String)
参数-P1
深度-当前类以及子类&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202310091525223.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202310091526271.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;h2-3-&quot;&gt;&lt;a name=&quot;3、修复方案&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、修复方案&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;官方没有提供标准的修复方案，但是在commit中找到了所谓的安全管理器的实现，文档中也提示需要在保证安全的情况下可使用&lt;br&gt;&lt;a href=&quot;https://github.com/dbcxy/fast-el/commit/ac0d5bdb95b5c5d52fe5df5a8b254e5e8ddd8a38&quot;&gt;https://github.com/dbcxy/fast-el/commit/ac0d5bdb95b5c5d52fe5df5a8b254e5e8ddd8a38&lt;/a&gt;&lt;br&gt;1、使用官方提供的安全管理器&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dbcxy/fast-el/commit/ac0d5bdb95b5c5d52fe5df5a8b254e5e8ddd8a38&quot;&gt;https://github.com/dbcxy/fast-el/commit/ac0d5bdb95b5c5d52fe5df5a8b254e5e8ddd8a38&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://code.google.com/archive/p/fast-el/&quot;&gt;https://code.google.com/archive/p/fast-el/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/blockquote&gt;
</description><pubDate>Fri, 13 Oct 2023 14:01:35 +0800</pubDate></item><item><title>洞态IAST检测优化：阿里QLExpress组件表达式注入</title><link>https://uzzju.com/post/81.java</link><description>&lt;p&gt;1&lt;/p&gt;
</description><pubDate>Fri, 13 Oct 2023 14:00:55 +0800</pubDate></item><item><title>MacOS下高效记录会议纪要以及实时音频转文字解决方案</title><link>https://uzzju.com/post/80.java</link><description>&lt;h1 id=&quot;h1--&quot;&gt;&lt;a name=&quot;一、前言&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;一、前言&lt;/h1&gt;&lt;p&gt;&lt;strong&gt;本文解决了1个问题&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1、如何同时带着耳机，并且能够音频识别电脑播放/会议声音转文字，还能够接收麦克风。&lt;/p&gt;
&lt;p&gt;首先为什么会有这样一篇文章，其实大家不管是甲方还是乙方，特别是甲方，大部分时间其实都是被各种会议占满，需求评审，安全评估，安全培训等等等，那么乙方，更多的是与客户开会，或与甲方一样，公司内部开会，那么此时少不了的是会议纪要，可能有些会议比较枯燥，根本不会有人认真去听，但作为打工人来说 :)!&lt;/p&gt;
&lt;p&gt;领导：小高啊，那个会议纪要你整理一下然后发给我/客户&lt;/p&gt;
&lt;p&gt;我目前基本一周的会议特别多，不管是内部会议，还是外部会议，这时候就会有一个痛点，会议纪要怎么处理？&lt;br&gt;如果是旁听状态下还好，可以边听边记。&lt;br&gt;那么如果是主讲人呢？针对会上的问题，会上的内容无法汇总，也无法记录。&lt;/p&gt;
&lt;p&gt;当然目前针对腾讯会议，飞书会议等会议办公软件，其实都提供这样的解决方案，会议录制可直接转换成文字，但这相对来说比较繁琐。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;内部会议还好，外部会议总开个录屏，给人感觉不是特别好:)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;那么有没有一款软件，可以让我在开会时，自动帮我记录会议内容？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;华为MetaBook X Pro 就解决这样的问题，但是华为独占，做的也非常好，遥遥领先！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;尊贵的水果用户能否拥有这样的体验？&lt;/p&gt;
&lt;p&gt;本文会带来作为个人用户的解决方案（本文以水果人用户角度出发）&lt;/p&gt;
&lt;h1 id=&quot;h1--&quot;&gt;&lt;a name=&quot;二、前期调研与产品体验&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;二、前期调研与产品体验&lt;/h1&gt;&lt;p&gt;产品试用体验上，目前体验了以下几款产品&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;产品名&lt;/th&gt;
&lt;th&gt;下载地址&lt;/th&gt;
&lt;th&gt;产品形态&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Noted&lt;/td&gt;
&lt;td&gt;MACOS APP Store&lt;/td&gt;
&lt;td&gt;客户端/多形态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;语音备忘录日记本&lt;/td&gt;
&lt;td&gt;MACOS APP Store&lt;/td&gt;
&lt;td&gt;客户端&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;讯飞听见&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://huiji.iflyrec.com/&quot;&gt;在线录音转文字-录音整理-录音转写工具-讯飞听见会记 (iflyrec.com)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;客户端/多形态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;通义听悟（阿里）&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://tingwu.aliyun.com/&quot;&gt;通义听悟 - 你的工作学习AI助手 (aliyun.com)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;浏览器/浏览器插件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;先说实际体验&lt;/p&gt;
&lt;h2 id=&quot;h2-1-noted&quot;&gt;&lt;a name=&quot;1、Noted&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、Noted&lt;/h2&gt;&lt;p&gt;总体感觉比较轻量化，并且没有账号体系，macos原生使用Icloud进行同步&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270115079.png&quot; alt=&quot;image-20230627005250476&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270115969.png&quot; alt=&quot;image-20230627005308039&quot;&gt;&lt;/p&gt;
&lt;p&gt;付费，价格如下图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270115546.png&quot; alt=&quot;image-20230627005516656&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;h3-1-1-&quot;&gt;&lt;a name=&quot;1.1、优点&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.1、优点&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;轻量化&lt;/li&gt;&lt;li&gt;编写&lt;/li&gt;&lt;li&gt;简单易用&lt;/li&gt;&lt;/ul&gt;
&lt;h3 id=&quot;h3-1-2-&quot;&gt;&lt;a name=&quot;1.2、缺点&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.2、缺点&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;语音转文字并不是特别准&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;见下图&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116958.png&quot; alt=&quot;image-20230627005830726&quot;&gt;&lt;/p&gt;
&lt;p&gt;这是来自我在一场面试时记录的内容，这里是求职者在介绍学校，但可以发现，错别字非常严重，另外完整记录下来，可读性基本为0。&lt;/p&gt;
&lt;h2 id=&quot;h2-2-&quot;&gt;&lt;a name=&quot;2、通义听悟（阿里）&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、通义听悟（阿里）&lt;/h2&gt;&lt;p&gt;由于没有客户端，所以跳过&lt;/p&gt;
&lt;h2 id=&quot;h2-3-&quot;&gt;&lt;a name=&quot;3、讯飞听见&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、讯飞听见&lt;/h2&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116961.png&quot; alt=&quot;image-20230627005923027&quot;&gt;&lt;/p&gt;
&lt;p&gt;科大讯飞目前是体验下来针对会议纪要最好的一个产品，毕竟做语音识别这么多年的大厂了。&lt;/p&gt;
&lt;p&gt;来看看语音识别的能力&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116610.png&quot; alt=&quot;image-20230627010408520&quot;&gt;&lt;/p&gt;
&lt;p&gt;总体来说，转文字的识别率还是很高的，并且准确率也还行。&lt;/p&gt;
&lt;p&gt;实际会议使用上发现也不错&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116325.png&quot; alt=&quot;image-20230627010530917&quot;&gt;&lt;/p&gt;
&lt;p&gt;缺点呢就是，加钱！&lt;/p&gt;
&lt;h2 id=&quot;h2-4-&quot;&gt;&lt;a name=&quot;4、总结&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4、总结&lt;/h2&gt;&lt;p&gt;目前会继续体验《讯飞听见》和《Noted》这两款产品，想看看一款好的产品能做到什么程度。&lt;/p&gt;
&lt;p&gt;当然，一款好的产品，能够解决用户的痛点，帮助提升效率等，我觉得是值得付费的。&lt;/p&gt;
&lt;p&gt;今年也是大大小小购买了很多正版的产品，比如Macos下的超级右键，自动切换输入法等，虽然这些产品都有公开的破解版可供下载，但如果在允许的条件下，也可以对开发者进行支持。&lt;/p&gt;
&lt;h2 id=&quot;h2-5-&quot;&gt;&lt;a name=&quot;5、遇到的问题&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5、遇到的问题&lt;/h2&gt;&lt;p&gt;其实在体验的过程中发现1个很严重的问题，如果不带耳机的情况下，外放进行电脑声音以及麦克风转文字的方案是可行的，但是如果使用耳机，那么常规的方案就不行了，至少我在macos的尝试下以及，阿里的听悟，科大讯飞，都没有见到能解决这个场景的，这也是本文带来的解决方案。&lt;/p&gt;
&lt;p&gt;场景举例&lt;/p&gt;
&lt;p&gt;1、现在需要使用腾讯会议开会，带着耳机&lt;/p&gt;
&lt;p&gt;需要实现的内容&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;戴耳机的情况下需要能够识别电脑腾讯会议音频输出并且转文字&lt;/li&gt;&lt;li&gt;戴耳机的情况下能够接受耳机的麦克风音频输入并且转文字&lt;/li&gt;&lt;/ul&gt;
&lt;h1 id=&quot;h1--&quot;&gt;&lt;a name=&quot;三、如何在使用耳机的情况下同时录制电脑的声音以及耳机的麦克风&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;三、如何在使用耳机的情况下同时录制电脑的声音以及耳机的麦克风&lt;/h1&gt;&lt;h2 id=&quot;h2-1-loopback&quot;&gt;&lt;a name=&quot;1、LoopBack&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、LoopBack&lt;/h2&gt;&lt;p&gt;这个问题的解决方案是使用LoopBack创建一个虚拟的音频设备，来解决该问题。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116861.png&quot; alt=&quot;image-20230627011057975&quot;&gt;&lt;/p&gt;
&lt;p&gt;再安装完成后Macos下会多出一个虚拟的音频驱动，打开LoopBack开始配置&lt;/p&gt;
&lt;h2 id=&quot;h2-2-loopback-&quot;&gt;&lt;a name=&quot;2、LoopBack配置&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、LoopBack配置&lt;/h2&gt;&lt;p&gt;点击下方的&lt;code&gt;New Virtual Device&lt;/code&gt;来新建一个设备&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116523.png&quot; alt=&quot;image-20230627011213155&quot;&gt;&lt;/p&gt;
&lt;p&gt;配置如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116060.png&quot; alt=&quot;image-20230627011142056&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sources&lt;/code&gt;默认即可，再&lt;code&gt;output&lt;/code&gt;中新增一个输出，监听中新增并选择耳机，我这里是AirPods Pro，所以选择自己的耳机名字。&lt;/p&gt;
&lt;p&gt;随后在讯飞听见配置如下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116115.png&quot; alt=&quot;image-20230627011449964&quot;&gt;&lt;/p&gt;
&lt;p&gt;这样配置后的效果&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;能够同时将电脑的音频输出与耳机的麦克风同时音频转文字，解决了上述的痛点。&lt;/li&gt;&lt;/ul&gt;
&lt;h2 id=&quot;h2-3-&quot;&gt;&lt;a name=&quot;3、最终效果&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、最终效果&lt;/h2&gt;&lt;p&gt;录制电脑音频&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116953.png&quot; alt=&quot;image-20230627011511871&quot;&gt;&lt;/p&gt;
&lt;p&gt;耳机语音输入&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/img/202306270116886.png&quot; alt=&quot;image-20230627011537526&quot;&gt;&lt;/p&gt;
</description><pubDate>Tue, 27 Jun 2023 11:19:57 +0800</pubDate></item><item><title> Windows11 LogonUI.exe 系统在应用程序中检测到基于堆栈都缓冲区溢出，溢出允许恶意用户获得此应用程序都控制。</title><link>https://uzzju.com/post/79.java</link><description>&lt;h1 id=&quot;h1-u95EEu9898&quot;&gt;&lt;a name=&quot;问题&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;问题&lt;/h1&gt;&lt;p&gt;LogonUI.exe系统错误&lt;/p&gt;
&lt;p&gt;系统在应用程序中检测到基于堆栈都缓冲区溢出，溢出允许恶意用户获得此应用程序都控制。&lt;/p&gt;
&lt;p&gt;事情线：2023年6月3日一整天直至次日凌晨2点，我都不在家，次日凌晨2点（6月4日）回到家中发现一直运行中都电脑出现这个提示。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202306041357775.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;描述：&lt;code&gt;LogonUI.exe&lt;/code&gt; 是 Windows 操作系统中的一个关键组件，它用于管理登录过程中显示的用户界面。”LogonUI” 实际上是 “Login User Interface” 的缩写，这就是它的主要职责：提供用户登录界面。&lt;/p&gt;
&lt;p&gt;当你启动 Windows 电脑时，&lt;code&gt;LogonUI.exe&lt;/code&gt; 将显示一个屏幕，让你输入用户名和密码或者选择一个用户账户进行登录。如果你的电脑设置了锁屏，那么在你退出锁屏并返回到 Windows 时，同样是 &lt;code&gt;LogonUI.exe&lt;/code&gt; 提供的用户界面让你输入密码。&lt;/p&gt;
&lt;p&gt;因此，如果 &lt;code&gt;LogonUI.exe&lt;/code&gt; 发生错误或者被破坏，用户可能无法正常登录到系统。在某些情况下，错误可能导致系统无法正常启动，或者在登录过程中出现问题。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Google尝试了很多方法都没什么用，推荐B站都文章：&lt;a href=&quot;https://www.bilibili.com/read/cv22299902&quot;&gt;https://www.bilibili.com/read/cv22299902&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;h1-u89E3u51B3u529Eu6CD5&quot;&gt;&lt;a name=&quot;解决办法&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;解决办法&lt;/h1&gt;&lt;h2 id=&quot;h2-1-windows11-&quot;&gt;&lt;a name=&quot;1、进入Windows11 高级启动&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、进入Windows11 高级启动&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;注意：不要进PE，我自己做了一个大白菜PE，但是进PE无法操作这些东西，切没有SFC，总结就是不要进PE，没有用&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;开机后，进入Windows，弹出LogonUI.exe都报错后就长按电源，强制关机，反复3次左右，就会自动加载Windows高级启动&lt;/p&gt;
&lt;h2 id=&quot;h2-2-&quot;&gt;&lt;a name=&quot;2、修复&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、修复&lt;/h2&gt;&lt;p&gt;在高级模式中打开CMD终端，输入下面都命令&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sfc /scannow &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时会自动修复&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202306041403494.png&quot; alt=&quot;image-20230604140355461&quot;&gt;&lt;/p&gt;
&lt;p&gt;随后重启会自动进入Windows安全模式，然后Windows的窗口桌面一直都是无响应，鼠标无法点击，不用管，直接WIN+R打开CMD。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202306041404424.png&quot; alt=&quot;image-20230604140459392&quot;&gt;&lt;/p&gt;
&lt;p&gt;然后再重启，就修复完毕了，就能自动进入系统&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage202306041406132.png&quot; alt=&quot;image-20230604140652078&quot;&gt;&lt;/p&gt;
</description><pubDate>Sun, 04 Jun 2023 14:11:11 +0800</pubDate></item><item><title>Java-SQL注入</title><link>https://uzzju.com/post/78.java</link><description>&lt;h2 id=&quot;h2-1-jdbc&quot;&gt;&lt;a name=&quot;1、JDBC&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、JDBC&lt;/h2&gt;&lt;h3 id=&quot;h3-1-1-statement&quot;&gt;&lt;a name=&quot;1.1、Statement&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.1、Statement&lt;/h3&gt;&lt;p&gt;创建连接对象使用&lt;code&gt;CreateStatement()&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Statement stmt = null;
try {
   stmt = conn.createStatement( );
   . . .
}
catch (SQLException e) {
   . . .
}
finally {
   stmt.close();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JDBC使用Statement是不安全的，需要程序员做好过滤，所以一般使用JDBC的程序员会更喜欢使用PrepareStatement做预编译，预编译不仅提高了程序执行的效率，还提高了安全性。&lt;/p&gt;
&lt;h4 id=&quot;h4--sql-&quot;&gt;&lt;a name=&quot;常见SQL场景-语句拼接&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;常见SQL场景-语句拼接&lt;/h4&gt;&lt;p&gt;使用&lt;code&gt;Statement&lt;/code&gt;来操作数据库比较常见的场景是直接使用&lt;code&gt;+&lt;/code&gt;拼接SQL语句，如下图&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822115709.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Java&quot;&gt;@GetMapping(&amp;quot;/vul1&amp;quot;)  
public String vul1(String id) {  

    StringBuilder result = new StringBuilder();  

    try {  
        Class.forName(&amp;quot;com.mysql.cj.jdbc.Driver&amp;quot;);  
        Connection conn = DriverManager.getConnection(db_url, db_user, db_pass);  

        Statement stmt = conn.createStatement();  
        String sql = &amp;quot;select * from users where id = &amp;#39;&amp;quot; + id + &amp;quot;&amp;#39;&amp;quot;;  
        log.info(&amp;quot;[vul] 执行SQL语句： &amp;quot; + sql);  
        ResultSet rs = stmt.executeQuery(sql);  

        while (rs.next()) {  
            String res_name = rs.getString(&amp;quot;user&amp;quot;);  
            String res_pass = rs.getString(&amp;quot;pass&amp;quot;);  
            String info = String.format(&amp;quot;查询结果 %s: %s&amp;quot;, res_name, res_pass);  
            result.append(info);  
        }  

        rs.close();  
        stmt.close();  
        conn.close();  
        return result.toString();  

    } catch (Exception e) {  
        // 输出错误，用于报错注入  
        return e.toString();  
    }  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如&lt;code&gt;String id&lt;/code&gt;获取的参数为1，那么此时的SQL语句为&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select * from users where id = &amp;#39;1&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为这里并未对&lt;code&gt;String id&lt;/code&gt;参数进行过滤，所以传入&lt;code&gt;&amp;#39;and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)--%20+&lt;/code&gt;就会造成SQL注入，那么此时的语句变成下面这样&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-mysql&quot;&gt;select * from users where id = &amp;#39;&amp;#39;and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)--%20+&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到传入的单引号闭合了前面的单引号，并且最后使用–+注释原来的单引号，这样就导致了SQL注入。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822120107.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tips: 不过这里做一个思考，Java是一个强类型的语言，那么在使用&lt;code&gt;id&lt;/code&gt;来代表参数，那么大概率接收的是一个&lt;code&gt;int&lt;/code&gt;类型的值，我认为如果站在java开发的角度上想，这里如果定义为&lt;code&gt;int id&lt;/code&gt;是不是就不会造成注入了呢？&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822120338.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;手动修改一下这里的代码，然后启动&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822120435.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;很显然，这里报错了，因为是类型转换的问题，我们传入的Str没办法转成int，所以这里及时存在SQL注入，在这种类型的限制下，也没有办法进行SQL语句拼接&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;h3-1-2-preparedstatement&quot;&gt;&lt;a name=&quot;1.2、PreParedStatement&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1.2、PreParedStatement&lt;/h3&gt;&lt;p&gt;PrepareStatement与Statement的区别对SQL语句进行预编译处理，预编译的好处除了在一定程度上防止SQL注入之外，还减少了SQL语句的编译次数，有效的提高了性能，而SQL注入只对编译过程有破坏作用，执行阶段只是把输入串作为数据处理，不需要再对SQL语句进行解析，因此解决了注入问题。&lt;/p&gt;
&lt;p&gt;因为SQL语句编译阶段是进行词法分析、语法分析、语义分析等过程的，也就是说编译过程识别了关键字、执行逻辑之类的东西，编译结束了这条SQL语句能干什么就定了。而在编译之后加入注入的部分，就已经没办法改变执行逻辑了，这部分就只能是相当于输入字符串被处理&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String sql = &amp;quot;select * from users where id = ?&amp;quot;;
PreparedStatement st = conn.prepareStatement(sql);
st.setString(1, id);
ResultSet rs = st.executeQuery();&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;h4-statement-preparestatement-&quot;&gt;&lt;a name=&quot;Statement与prepareStatement的区别&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;Statement与prepareStatement的区别&lt;/h4&gt;&lt;p&gt;1、prepareStatement会先初始化SQL，先把这个SQL提交到数据库中进行预处理，多次使用可提高效率，而Statement不会初始化，没有预处理，每次都是从0开始执行SQL。&lt;br&gt;2、prepareStatement可以在SQL中用?替换变量，而createStatement不支持 ? 替换变量，只能在sql中拼接参数&lt;br&gt;3、在使用功能上的区别&lt;br&gt;如果想要删除三条数据&lt;br&gt;对于createStatement，需要写三条语句&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String sql = &amp;quot;delete from category where id = 2&amp;quot;  ; 
String sql = &amp;quot;delete from category where id = 3&amp;quot;  ; 
String sql = &amp;quot;delete from category where id = 7&amp;quot;  ;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而prepareStatement，通过set不同数据只需要生成一次执行计划，可以重用&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String sql = &amp;quot;delete from category where id = ？&amp;quot;  ;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;PreparedStatement是预编译的,对于批量处理可以大大提高效率.也叫JDBC存储过程。&lt;/li&gt;&lt;li&gt;使用createStatement 对象。在对数据库只执行一次性存取的时侯，用 createStatement对象进行处理。PreparedStatement对象的开销比createStatement大，对于一次性操作并不会带来额外的好处。&lt;/li&gt;&lt;li&gt;createStatement每次执行sql语句，相关数据库都要执行sql语句的编译，preparedstatement是预编译得,preparedstatement支持批处理&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;br&gt;Statement每次执行sql语句，数据库都要执行sql语句的编译，最好用于仅执行一次查询并返回结果的情形，效率高于PreparedStatement.但存在sql注入风险。PreparedStatement是预编译执行的。在执行可变参数的一条SQL时，PreparedStatement要比Statement的效率高，因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率高。安全性更好，有效防止SQL注入的问题。对于多次重复执行的语句，使用prepareStatement，因为数据库会对sql语句进行预编译，下次执行相同的sql语句时，数据库端不会再进行预编译了，而直接用数据库的缓冲区，提高数据访问的效率（但尽量采用使用？号的方式传递参数），如果sql语句只执行一次，以后不再复用。&lt;/p&gt;
&lt;h4 id=&quot;h4--preparestatement-sql-&quot;&gt;&lt;a name=&quot;为什么预编译（PrepareStatement）可以防止sql注入&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;为什么预编译（PrepareStatement）可以防止sql注入&lt;/h4&gt;&lt;p&gt;原理是采用了预编译的方法，先将SQL语句中可被客户端控制的参数集进行编译，生成对应的临时变量集，再使用对应的设置方法，为临时变量集里面的元素进行赋值，赋值函数&lt;code&gt;setString()&lt;/code&gt;，会对传入的参数进行强制类型检查和安全检查，所以就避免了SQL注入的产生。下面具体分析。&lt;/p&gt;
&lt;p&gt;Statement之所以会被sql注入是因为SQL语句结构发生了变化。比如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SQL = “SELECT * FROM users WHERE (name = ‘” + userName + “’) and (pw = ‘”+ passWord +”’);”

//如果恶意填入
userName = “1’ OR ‘1’=’1”;
passWord = “1’ OR ‘1’=’1”;

//将变成
SQL = SELECT * FROM users WHERE (name = ‘1’ OR ‘1’=’1’) and (pw = ‘1’ OR ‘1’=’1’);

//相当于
SQL = SELECT * FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sql&lt;/p&gt;
&lt;p&gt;而Preparement样式为&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM users WHERE userName=? and passWord=?&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sql&lt;/p&gt;
&lt;p&gt;该SQL语句会在得到用户的输入之前先用数据库进行预编译，这样的话不管用户输入什么用户名和密码的判断始终都是并的逻辑关系，防止了SQL注入。&lt;/p&gt;
&lt;p&gt;简单总结，参数化能防注入的原因在于，&lt;strong&gt;语句是语句，参数是参数&lt;/strong&gt;，参数的值并不是语句的一部分，数据库只按语句的语义跑。&lt;/p&gt;
&lt;h4 id=&quot;h4-u9884u7F16u8BD1u6CE8u5165u573Au666F&quot;&gt;&lt;a name=&quot;预编译注入场景&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;预编译注入场景&lt;/h4&gt;&lt;h5 id=&quot;h5-u62FCu63A5u8BEDu53E5&quot;&gt;&lt;a name=&quot;拼接语句&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;拼接语句&lt;/h5&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822140140.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public String vul2(String id) {  

    StringBuilder result = new StringBuilder();  

    try {  
        Class.forName(&amp;quot;com.mysql.cj.jdbc.Driver&amp;quot;);  
        Connection conn = DriverManager.getConnection(db_url, db_user, db_pass);  

        String sql = &amp;quot;select * from users where id = &amp;quot; + id;  
        log.info(&amp;quot;[vul] 执行SQL语句： &amp;quot; + sql);  
        PreparedStatement st = conn.prepareStatement(sql);  
        ResultSet rs = st.executeQuery();  

        while (rs.next()) {  
            String res_name = rs.getString(&amp;quot;user&amp;quot;);  
            String res_pass = rs.getString(&amp;quot;pass&amp;quot;);  
            String info = String.format(&amp;quot;查询结果%n %s: %s%n&amp;quot;, res_name, res_pass);  
            result.append(info);  
        }  

        rs.close();  
        st.close();  
        conn.close();  
        return result.toString();  

    } catch (Exception e) {  
        return e.toString();  
    }  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在代码中可以看到，这里使用了prepareStatement对SQL语句进行预编译处理，但是还是使用+号拼接的方式拼接了前端传入的参数，没有使用?号做占位符，这样就导致了prepareStatement预编译处理防止SQL注入失效了。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822140343.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822140356.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;在控制台中可以看到打印的SQL语句&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822140417.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tips: 来看看使用?号占位符的时候SQL语句的样子&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822140637.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822162503.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;不难发现使用?号占位符之后，传入的参数还是会在’’中间，因为传入的只会当做字符串作为解析&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5 id=&quot;h5-like-&quot;&gt;&lt;a name=&quot;like语句&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;like语句&lt;/h5&gt;&lt;p&gt;新增一个方法，改一下代码&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822164558.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public String safe_test(String id) {  

    StringBuilder result = new StringBuilder();  
    try {  
        Class.forName(&amp;quot;com.mysql.cj.jdbc.Driver&amp;quot;);  
        Connection conn = DriverManager.getConnection(db_url, db_user, db_pass);  
        String sql_1 = &amp;quot;where user like &amp;#39;%&amp;quot; + id + &amp;quot;%&amp;#39;&amp;quot;;  
        String sql = &amp;quot;select * from users &amp;quot; + sql_1;  
        System.out.println(&amp;quot;拼接后语句为: &amp;quot; + sql);  
        PreparedStatement st = conn.prepareStatement(sql);  
        log.info(&amp;quot;[safe] 执行SQL语句： &amp;quot; + st);  
        ResultSet rs = st.executeQuery();  
        result.append(&amp;quot;成功&amp;quot;);  
        rs.close();  
        st.close();  
        conn.close();  
        return result.toString();  

    } catch (Exception e) {  
        return e.toString();  
    }  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822164645.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;然后构造参数请求接口&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822173332.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;GET /SQLI/JDBC/test1?id=1%25&amp;#39;+or+sleep(3)%23 HTTP/1.1
Host: 192.168.0.35:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: JSESSIONID=F445CA5F0CF6B1BE279BC0FA438873E6

&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;h5-in-&quot;&gt;&lt;a name=&quot;in语句&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;in语句&lt;/h5&gt;&lt;p&gt;在in当中使用拼接而不使用占位符做预编译的原因是因为很多时候无法确定Ids里含有多少个对象&lt;br&gt;例如下面的语句&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select * from users where id in (2,3);
# 使用占位符就需要
select * from users where id in (?, ?);
# 那么有多个语句呢？如何动态的更新？&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;稍微改一下代码&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822174558.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822174846.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h5 id=&quot;h5-orderby-&quot;&gt;&lt;a name=&quot;orderby语句&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;orderby语句&lt;/h5&gt;&lt;p&gt;首先为什么预编译无法防止order by注入，因为order by的子域后面需要加上字段名或者字段位置，但是字段名是不能带引号的，否则会被认为是一个字符串，但是使用PreapareStatement会强制给参数加上单引号&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822165428.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;但是如果给order by加上单引号，可以发现order by的排序功能失效了&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822165537.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;这里有三个对照组可以参考，所以在使用order by语句的时候必须拼接Statement，所以如果使用order by的话，需要对传入的参数进行过滤。&lt;/p&gt;
&lt;h2 id=&quot;h2-2-mybatis&quot;&gt;&lt;a name=&quot;2、Mybatis&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、Mybatis&lt;/h2&gt;&lt;h3 id=&quot;h3-2-1-mybatis-&quot;&gt;&lt;a name=&quot;2.1、mybatis的占位符#和$&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.1、mybatis的占位符#和$&lt;/h3&gt;&lt;p&gt;Mybatis下有两种传参方式，分别是${}以及#{}，&lt;br&gt;其区别是&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用${}的方式传参，mybatis是将传入的参数直接拼接到SQL语句上，&lt;/li&gt;&lt;li&gt;使用#{}传参则是和JDBC一样转换为占位符来进行预编译&lt;h3 id=&quot;h3-2-2-&quot;&gt;&lt;a name=&quot;2.2、#与$的区别&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.2、#与$的区别&lt;/h3&gt;&lt;h4 id=&quot;h4-1-sql-&quot;&gt;&lt;a name=&quot;1、#和$哪个能防止SQL注入&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、#和$哪个能防止SQL注入&lt;/h4&gt;&lt;/li&gt;&lt;li&gt;#号传入的参数在SQL中显示为字符串 &lt;/li&gt;&lt;li&gt;$号传入的参数在SqL中直接显示为传入的值&lt;/li&gt;&lt;li&gt;#号方式能够很大程度防止sql注入，$方式无法防止Sql注入&lt;/li&gt;&lt;/ul&gt;
&lt;h4 id=&quot;h4-2-sql-&quot;&gt;&lt;a name=&quot;2、传入的参数在SQL中显示不同&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、传入的参数在SQL中显示不同&lt;/h4&gt;&lt;p&gt;1、传入的参数在SQL中显示为字符串（当成一个字符串），会对自动传入的数据加一个双引号。&lt;/p&gt;
&lt;p&gt;例：使用以下SQL&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select id,name,age from student where id =#{id}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当我们传递的参数id为 “1” 时，上述 sql 的解析为：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select id,name,age from student where id =&amp;quot;1&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$传入的参数在SqL中直接显示为传入的值&lt;br&gt;例：使用以下SQL&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select id,name,age from student where id =${id}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当我们传递的参数id为 “1” 时，上述 sql 的解析为：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select id,name,age from student where id =1&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;h4-3-&quot;&gt;&lt;a name=&quot;3、实现方式不同&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、实现方式不同&lt;/h4&gt;&lt;p&gt;1、$号作用相当于是字符串拼接&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822170332.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;相当于使用StringBuffer的append方法将&lt;code&gt;${username}$&lt;/code&gt;追加在&lt;br&gt;select username,pass from t_login where username=后面，拼接在一起。&lt;br&gt;2、#号作用相当于变量值替换&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822170432.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;相当于使用PreparedStement接口来对#{username}#来进行赋值操作。&lt;/p&gt;
&lt;h4 id=&quot;h4-4-&quot;&gt;&lt;a name=&quot;4、使用场景不同&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4、使用场景不同&lt;/h4&gt;&lt;p&gt;1、在sql语句中，如果要接收传递过来的变量的值的话，必须使用#。因为使用#是通过PreparedStement接口来操作，可以防止sql注入，并且在多次执行sql语句时可以提高效率。  &lt;/p&gt;
&lt;p&gt;2、只是简单的字符串拼接而已，所以要特别小心sql注入问题。对于sql语句中非变量部分，那就可以使用$，比如$方式一般用于传入数据库对象(如传入表名)。&lt;br&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select * from `${tableName}$` &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于不同的表执行统一的查询操作时，就可以使用$来完成。&lt;/p&gt;
&lt;h4 id=&quot;h4-5-sql-sql-&quot;&gt;&lt;a name=&quot;5、可以防止SQL注入的风险（语句的拼接）；但$无法防止Sql注入。&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5、可以防止SQL注入的风险（语句的拼接）；但$无法防止Sql注入。&lt;/h4&gt;&lt;h4 id=&quot;h4-6-&quot;&gt;&lt;a name=&quot;6、大多数情况下还是经常使用#，一般能用#的就别用$&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;6、大多数情况下还是经常使用#，一般能用#的就别用$&lt;/h4&gt;&lt;p&gt;例：MyBatis排序时使用order by 动态参数时需要注意，用$而不是#。&lt;/p&gt;
&lt;h3 id=&quot;h3-2-3-mybatis-tips&quot;&gt;&lt;a name=&quot;2.3、mybatis的小Tips&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.3、mybatis的小Tips&lt;/h3&gt;&lt;h4 id=&quot;h4-1-mybatis-order-by-code-code-&quot;&gt;&lt;a name=&quot;1、为什么mybatis order by不能使用&lt;code&gt;#&lt;/code&gt;号&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、为什么mybatis order by不能使用&lt;code&gt;#&lt;/code&gt;号&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;select * from users order by id;
select * from users order by &amp;#39;id&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最直观的两条SQL语句就可以证明为什么不能使用#号&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822170858.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;这里很明显能够发现，当加上单引号之后，排序就失效了，这是为什么呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;1、在Mysql中，如果order by后面是一个字符串，那么mysql根据一个常量列进行排序，但是所有常量的值都相等，所以就不会进行排序&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt;2、Mybatis在使用#号引用参数的时候，会自动给参数两端加上引号，导致排序失效，因此MyBatis中使用Order by推荐使用$号&lt;/p&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;h4 id=&quot;h4-2-&quot;&gt;&lt;a name=&quot;2、为什么表名需要使用$符号？&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、为什么表名需要使用$符号？&lt;/h4&gt;&lt;p&gt;因为表名不允许使用引号，直接引用就报错，但是使用#号又会给表名加上单引号，导致报错，所以推荐使用$号&lt;/p&gt;
&lt;h4 id=&quot;h4-3-mybatis-sql-&quot;&gt;&lt;a name=&quot;3、mybatis是如何做到防止sql注入的&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、mybatis是如何做到防止sql注入的&lt;/h4&gt;&lt;p&gt;【底层实现原理】在框架底层，是JDBC中的PreparedStatement类在起作用，PreparedStatement是我们很熟悉的Statement的子类，它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性，而且在多次执行同一个SQL时，能够提高效率。原因是SQL已编译好，再次执行时无需再编译。&lt;/p&gt;
&lt;h3 id=&quot;h3-2-4-mybatis-&quot;&gt;&lt;a name=&quot;2.4、mybatis注入场景&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2.4、mybatis注入场景&lt;/h3&gt;&lt;h4 id=&quot;h4-1-&quot;&gt;&lt;a name=&quot;1、使用${}占位&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、使用${}占位&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822171357.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;随后访问接口构造报错函数&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822171857.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;try catch堆栈信息&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822171926.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;h4-2-order-by-&quot;&gt;&lt;a name=&quot;2、order by注入&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、order by注入&lt;/h4&gt;&lt;p&gt;由于使用 #{} 会将对象转成字符串，形成 order by “user” desc 造成错误，因此很多研发会采用${}来解决，从而造成SQL注入&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822172242.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220822172358.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;orderby在Mybatis如下&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220909164727.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;请求接口查看SQL执行的语句&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220909164800.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220909164815.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;然后手动执行一下SQL语句就知道差异是什么了&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220909164854.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;可以看到，在使用单引号加上order by排序的字段之后，orderby的排序功能直接失效，那么预编译处理的参数传进去之后肯定是有单引号的，故此会造成SQL注入&lt;/p&gt;
&lt;h4 id=&quot;h4-3-in-like-&quot;&gt;&lt;a name=&quot;3、in与like语句&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、in与like语句&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220909171539.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220909171551.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;h2-3-hibernate&quot;&gt;&lt;a name=&quot;3、Hibernate&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、Hibernate&lt;/h2&gt;&lt;h3 id=&quot;h3-1-hibernate&quot;&gt;&lt;a name=&quot;1、什么是Hibernate&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;1、什么是Hibernate&lt;/h3&gt;&lt;p&gt;Hibernate是一个开源的对象关系映射（ORM：Object Relation Mapping）框架，对JDBC进行了非常轻量级的对象封装，采用映射元数据（配置文件）来描述对象-关系的映射细节，是一个全自动的orm框架。hibernate可以自动生成SQL语句，自动执行，使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。&lt;/p&gt;
&lt;h3 id=&quot;h3-2-orm-&quot;&gt;&lt;a name=&quot;2、什么是ORM框架&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;2、什么是ORM框架&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;ORM是一种思想&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;O代表的是Objcet&lt;/li&gt;&lt;li&gt;R代表的是Relative&lt;/li&gt;&lt;li&gt;M代表的是Mapping&lt;br&gt;ORM-&amp;gt;对象关系映射….ORM关注是&lt;strong&gt;对象与数据库中的列的关系&lt;/strong&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220913121334.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h3 id=&quot;h3-3-hibermate-&quot;&gt;&lt;a name=&quot;3、Hibermate架构&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;3、Hibermate架构&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;创建持久化类&lt;/li&gt;&lt;li&gt;创建对象-关系映射文件&lt;/li&gt;&lt;li&gt;创建Hibernate配置文件&lt;/li&gt;&lt;li&gt;通过Hibernate API编写访问数据库的代码&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20220913121134.png&quot; alt=&quot;&quot;&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;h3 id=&quot;h3-4-hql-&quot;&gt;&lt;a name=&quot;4、HQL注入场景&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4、HQL注入场景&lt;/h3&gt;&lt;p&gt;Hibernate查询方式主要有get/load主键查询，对象导航查询、HQL查询、Criteria查询、SQLQuery本地SQL查询。&lt;strong&gt;审计的方法主要是搜索createQuery()、createSQLQuery、criteria、createNativeQuery()，查看与其相关的上下文，检查是否存在拼接sql&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id=&quot;h4-4-1-demo&quot;&gt;&lt;a name=&quot;4.1、代码Demo&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.1、代码Demo&lt;/h4&gt;&lt;p&gt;整体目录结构&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013143542.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h5 id=&quot;h5-4-1-1-address-java&quot;&gt;&lt;a name=&quot;4.1.1、Address.java&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.1.1、Address.java&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;package com.uzju.hsql;  

import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.Id;  
import javax.persistence.OneToOne;  
import javax.persistence.PrimaryKeyJoinColumn;  
import javax.persistence.Table;  

import org.hibernate.annotations.GenericGenerator;  
import org.hibernate.annotations.Parameter;  

@Entity  
@Table(name = &amp;quot;ADDRESS&amp;quot;)  
public class Address {  

    @Id  
    @Column(name = &amp;quot;emp_id&amp;quot;, unique = true, nullable = false)  
    @GeneratedValue(generator = &amp;quot;gen&amp;quot;)  
    @GenericGenerator(name = &amp;quot;gen&amp;quot;, strategy = &amp;quot;foreign&amp;quot;,  
            parameters = { @Parameter(name = &amp;quot;property&amp;quot;, value = &amp;quot;employee&amp;quot;) })  
    private long id;  

    @Column(name = &amp;quot;address_line1&amp;quot;)  
    private String addressLine1;  

    @Column(name = &amp;quot;zipcode&amp;quot;)  
    private String zipcode;  

    @Column(name = &amp;quot;city&amp;quot;)  
    private String city;  

    @OneToOne  
    @PrimaryKeyJoinColumn    private Employee employee;  

    public long getId() {  
        return id;  
    }  

    public void setId(long id) {  
        this.id = id;  
    }  

    public String getAddressLine1() {  
        return addressLine1;  
    }  

    public void setAddressLine1(String addressLine1) {  
        this.addressLine1 = addressLine1;  
    }  

    public String getZipcode() {  
        return zipcode;  
    }  

    public void setZipcode(String zipcode) {  
        this.zipcode = zipcode;  
    }  

    public String getCity() {  
        return city;  
    }  

    public void setCity(String city) {  
        this.city = city;  
    }  

    public Employee getEmployee() {  
        return employee;  
    }  

    public void setEmployee(Employee employee) {  
        this.employee = employee;  
    }  

}&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;h5-4-1-2-employee-java&quot;&gt;&lt;a name=&quot;4.1.2、Employee.java&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.1.2、Employee.java&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;package com.uzju.hsql;  

import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.GenerationType;  
import javax.persistence.Id;  
import javax.persistence.OneToOne;  
import javax.persistence.Table;  

import org.hibernate.annotations.Cascade;  

@Entity  
@Table(name = &amp;quot;EMPLOYEE&amp;quot;)  
public class Employee {  

    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    @Column(name = &amp;quot;emp_id&amp;quot;)  
    private long id;  

    @Column(name = &amp;quot;emp_name&amp;quot;)  
    private String name;  

    @Column(name = &amp;quot;emp_salary&amp;quot;)  
    private double salary;  

    @OneToOne(mappedBy = &amp;quot;employee&amp;quot;)  
    @Cascade(value = org.hibernate.annotations.CascadeType.ALL)  
    private Address address;  

    public long getId() {  
        return id;  
    }  

    public void setId(long id) {  
        this.id = id;  
    }  

    public Address getAddress() {  
        return address;  
    }  

    public void setAddress(Address address) {  
        this.address = address;  
    }  

    public String getName() {  
        return name;  
    }  

    public void setName(String name) {  
        this.name = name;  
    }  

    public double getSalary() {  
        return salary;  
    }  

    public void setSalary(double salary) {  
        this.salary = salary;  
    }  

}&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;h5-4-1-3-hibernateutil-java&quot;&gt;&lt;a name=&quot;4.1.3、HibernateUtil.java&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.1.3、HibernateUtil.java&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;package com.uzju.hsql;  

import org.hibernate.SessionFactory;  
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;  
import org.hibernate.cfg.Configuration;  
import org.hibernate.service.ServiceRegistry;  

public class HibernateUtil {  

    private static SessionFactory sessionFactory;  

    private static SessionFactory buildSessionFactory() {  
        try {  
            // Create the SessionFactory from hibernate.cfg.xml  
            Configuration configuration = new Configuration();  
            configuration.configure(&amp;quot;hibernate.cfg.xml&amp;quot;);  
            System.out.println(&amp;quot;Hibernate Configuration loaded&amp;quot;);  

            ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();  
            System.out.println(&amp;quot;Hibernate serviceRegistry created&amp;quot;);  

            SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);  

            return sessionFactory;  
        }  
        catch (Throwable ex) {  
            System.err.println(&amp;quot;Initial SessionFactory creation failed.&amp;quot; + ex);  
            ex.printStackTrace();  
            throw new ExceptionInInitializerError(ex);  
        }  
    }  

    public static SessionFactory getSessionFactory() {  
        if(sessionFactory == null) sessionFactory = buildSessionFactory();  
        return sessionFactory;  
    }  
}&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;h5-4-1-4-hqlexamples-java&quot;&gt;&lt;a name=&quot;4.1.4、HQLExamples.java&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.1.4、HQLExamples.java&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;package com.uzju.hsql;  

import java.util.Arrays;  
import java.util.List;  

import org.hibernate.Query;  
import org.hibernate.Session;  
import org.hibernate.SessionFactory;  
import org.hibernate.Transaction;  

public class HQLExamples {  

    @SuppressWarnings(&amp;quot;unchecked&amp;quot;)  
    public static void main(String[] args) {  

        //Prep work  
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();  
        Session session = sessionFactory.getCurrentSession();  

        //HQL example - Get All Employees  
        Transaction tx = session.beginTransaction();  
        Query query = session.createQuery(&amp;quot;from Employee&amp;quot;);  
        List&amp;lt;Employee&amp;gt; empList = query.list();  
        for(Employee emp : empList){  
            System.out.println(&amp;quot;List of Employees::&amp;quot;+emp.getId()+&amp;quot;,&amp;quot;+emp.getAddress().getCity());  
        }  

        //HQL example - Get Employee with id  
        query = session.createQuery(&amp;quot;from Employee where id= :id&amp;quot;);  
        query.setLong(&amp;quot;id&amp;quot;, 3);  
        Employee emp = (Employee) query.uniqueResult();  
        System.out.println(&amp;quot;Employee Name=&amp;quot;+emp.getName()+&amp;quot;, City=&amp;quot;+emp.getAddress().getCity());  

//        //HQL pagination example  
//        query = session.createQuery(&amp;quot;from Employee&amp;quot;);  
//        query.setFirstResult(0); //starts with 0  
//        query.setFetchSize(2);  
//        empList = query.list();  
//        for(Employee emp4 : empList){  
//            System.out.println(&amp;quot;Paginated Employees::&amp;quot;+emp4.getId()+&amp;quot;,&amp;quot;+emp4.getAddress().getCity());  
//        }  
//  
//        //HQL Aggregate function examples  
//        query = session.createQuery(&amp;quot;select sum(salary) from Employee&amp;quot;);  
//        double sumSalary = (Double) query.uniqueResult();  
//        System.out.println(&amp;quot;Sum of all Salaries= &amp;quot;+sumSalary);  
//  
//        //HQL join examples  
//        query = session.createQuery(&amp;quot;select e.name, a.city from Employee e &amp;quot;  
//                + &amp;quot;INNER JOIN e.address a&amp;quot;);  
//        List&amp;lt;Object[]&amp;gt; list = query.list();  
//        for(Object[] arr : list){  
//            System.out.println(Arrays.toString(arr));  
//        }  
//  
//        //HQL group by and like example  
//        query = session.createQuery(&amp;quot;select e.name, sum(e.salary), count(e)&amp;quot;  
//                + &amp;quot; from Employee e where e.name like &amp;#39;%i%&amp;#39; group by e.name&amp;quot;);  
//        List&amp;lt;Object[]&amp;gt; groupList = query.list();  
//        for(Object[] arr : groupList){  
//            System.out.println(Arrays.toString(arr));  
//        }  
//  
//        //HQL order by example  
//        query = session.createQuery(&amp;quot;from Employee e order by e.id desc&amp;quot;);  
//        empList = query.list();  
//        for(Employee emp3 : empList){  
//            System.out.println(&amp;quot;ID Desc Order Employee::&amp;quot;+emp3.getId()+&amp;quot;,&amp;quot;+emp3.getAddress().getCity());  
//        }  

        //rolling back to save the test data        tx.rollback();  

        //closing hibernate resources  
        sessionFactory.close();  
    }  

}&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;h5-4-1-5-hibernate-cfg-xml&quot;&gt;&lt;a name=&quot;4.1.5、hibernate.cfg.xml&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.1.5、hibernate.cfg.xml&lt;/h5&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;  
&amp;lt;!DOCTYPE hibernate-configuration PUBLIC  
        &amp;quot;-//Hibernate/Hibernate Configuration DTD 3.0//EN&amp;quot;  
        &amp;quot;https://hibernate.org/dtd/hibernate-configuration-3.0.dtd&amp;quot;&amp;gt;  
&amp;lt;hibernate-configuration&amp;gt;  
    &amp;lt;session-factory&amp;gt;        &amp;lt;property name=&amp;quot;hibernate.connection.driver_class&amp;quot;&amp;gt;com.mysql.jdbc.Driver&amp;lt;/property&amp;gt;  
        &amp;lt;property name=&amp;quot;hibernate.connection.password&amp;quot;&amp;gt;root&amp;lt;/property&amp;gt;  
        &amp;lt;property name=&amp;quot;hibernate.connection.url&amp;quot;&amp;gt;jdbc:mysql://localhost/test&amp;lt;/property&amp;gt;  
        &amp;lt;property name=&amp;quot;hibernate.connection.username&amp;quot;&amp;gt;root&amp;lt;/property&amp;gt;  
        &amp;lt;property name=&amp;quot;hibernate.dialect&amp;quot;&amp;gt;org.hibernate.dialect.MySQLDialect&amp;lt;/property&amp;gt;  

        &amp;lt;property name=&amp;quot;hibernate.current_session_context_class&amp;quot;&amp;gt;thread&amp;lt;/property&amp;gt;  
        &amp;lt;property name=&amp;quot;hibernate.show_sql&amp;quot;&amp;gt;true&amp;lt;/property&amp;gt;  

        &amp;lt;mapping class=&amp;quot;com.uzju.hsql.Employee&amp;quot;/&amp;gt;  
        &amp;lt;mapping class=&amp;quot;com.uzju.hsql.Address&amp;quot;/&amp;gt;  
    &amp;lt;/session-factory&amp;gt;&amp;lt;/hibernate-configuration&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;h4-4-2-&quot;&gt;&lt;a name=&quot;4.2、拼接语句&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.2、拼接语句&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013152934.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String SQLInject = &amp;quot;1&amp;quot;;  
String SQL = &amp;quot;from Employee where id= &amp;quot; + SQLInject;  
List&amp;lt;Employee&amp;gt; emp = session.createQuery(SQL).list();  
for (Employee employee : emp){  
    System.out.println(employee.getName());  
    System.out.println(&amp;quot;=====&amp;quot;);  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013153013.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String SQLInject = &amp;quot;1 or 1 = 1&amp;quot;;  
String SQL = &amp;quot;from Employee where id= &amp;quot; + SQLInject;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013153117.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;h4-4-2-createsqlquery-&quot;&gt;&lt;a name=&quot;4.2、createSQLQuery查询&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.2、createSQLQuery查询&lt;/h4&gt;&lt;p&gt;Hibernate对原生SQL查询的支持和控制是通过SQLQuery接口实现的，这种方式弥补了HQL、Criterion查询的不足，其直接使用sql语句进行查询，在操作和使用上往往更加的自由和灵活，如果使用得当，数据库操作的效率还会得到不同程度的提升。一般复杂的sql都会用到它。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013154256.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;该方法与常规的SQL注入没什么区别，存在注入点直接拼接就可以造成注入，无条件限制。&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013154710.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;新版本hibernate已经弃用createSQLQuery()，可使用createNativeQuery()代替。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;h4-4-3-criteria-&quot;&gt;&lt;a name=&quot;4.3、Criteria注入&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.3、Criteria注入&lt;/h4&gt;&lt;p&gt;当查询数据时，人们往往需要设置查询条件。在SQL或HQL语句中，查询条件常常放在where子句中。此外，Hibernate还支持Criteria查询（Criteria Query），这种查询方式把查询条件封装为一个Criteria对象。在实际应用中，使用Session的createCriteria()方法构建一个org.hibernate.Criteria实例，然后把具体的查询条件通过Criteria的add()方法加入到Criteria实例中。这样，程序员可以不使用SQL甚至HQL的情况下进行数据查询。&lt;/p&gt;
&lt;h5 id=&quot;h5-4-3-1-criteria-query-&quot;&gt;&lt;a name=&quot;4.3.1、Criteria Query常用的查询限制方法&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;4.3.1、Criteria Query常用的查询限制方法&lt;/h5&gt;&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013155021.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013165032.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;&lt;img src=&quot;https://uzjumakdown-1256190082.cos.ap-guangzhou.myqcloud.com/UzJuMarkDownImage20221013165106.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;h3-5-hibernate-&quot;&gt;&lt;a name=&quot;5、Hibernate修复&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5、Hibernate修复&lt;/h3&gt;&lt;h4 id=&quot;h4-5-1-hibernate-&quot;&gt;&lt;a name=&quot;5.1、Hibernate参数绑定的方式&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.1、Hibernate参数绑定的方式&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;参数绑定优点&lt;/strong&gt;：&lt;br&gt;（1）安全性&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;防止用户恶意输入条件和恶意调用存储过程&lt;br&gt;（2）提高性能&lt;/li&gt;&lt;li&gt;底层采用JDBC的PreparedStatement预定义sql功能，后期查询直接从缓存中获取执行&lt;h5 id=&quot;h5-5-1-1-&quot;&gt;&lt;a name=&quot;5.1.1、按命名参数绑定（参数名字）&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.1.1、按命名参数绑定（参数名字）&lt;/h5&gt;在HQL语句中定义命名参数要用”:”开头&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;1 Query query=session.createQuery(“from User user where user.name=:username and user.age=:userage ”);
2 query.setString(“username”,name);
3 query.setInteger(“userage”,age);&lt;/code&gt;&lt;/pre&gt;
上面代码中用:username和:userage分别定义了命名参数，然后用Query接口的setXXX()方法设定名参数值，setXXX()方法包含两个参数，分别是命名参数名称和命名参数实际值。&lt;/li&gt;&lt;/ul&gt;
&lt;h5 id=&quot;h5-5-1-2-&quot;&gt;&lt;a name=&quot;5.1.2、按参数位置邦定&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.1.2、按参数位置邦定&lt;/h5&gt;&lt;p&gt;　在HQL查询语句中用”?”来定义参数位置，形式如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Query query=session.createQuery(“from User user where user.name=? and user.age =? ”);
query.setString(0,name);
query.setInteger(1,age);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同样使用setXXX()方法设定绑定参数，只不过这时setXXX()方法的第一个参数代表绑定参数在HQL语句中出现的位置编号（由0开始编号），第二个参数仍然代表参数实际值。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：在实际开发中，提倡使用按名称绑定命名参数，因为这不但可以提供非常好的程序可读性，而且也提高了程序的易维护性，因为当查询参数的位置发生改变时，按名称邦定名参 数的方式中是不需要调整程 序代码的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5 id=&quot;h5-5-1-3-setparameter-&quot;&gt;&lt;a name=&quot;5.1.3、setParameter()方法&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.1.3、setParameter()方法&lt;/h5&gt;&lt;p&gt;在Hibernate的HQL查询中可以通过setParameter()方法邦定任意类型的参数，如下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;String hql=”from User user where user.name=:customername ”;
Query query=session.createQuery(hql);
query.setParameter(“customername”,name,Hibernate.STRING);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如上面代码所示，setParameter()方法包含三个参数，分别是命名参数名称，命名参数实际值，以及命名参数映射类型。对于某些参数类型setParameter()方法可以根据参数值的Java类型，猜测出对应的映射类型，因此这时不需要显示写出映射类型，像上面的例子，可以直接这样写：&lt;/p&gt;
&lt;p&gt;query.setParameter(“customername”,name);但是对于一些类型就必须写明映射类型，比如java.util.Date类型，因为它会对应Hibernate的多种映射类型，比如Hibernate.DATA或者Hibernate.TIMESTAMP。&lt;/p&gt;
&lt;h5 id=&quot;h5-5-1-4-setproperties-&quot;&gt;&lt;a name=&quot;5.1.4、setProperties()方法&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.1.4、setProperties()方法&lt;/h5&gt;&lt;p&gt;在Hibernate中可以使用setProperties()方法，将命名参数与一个对象的属性值绑定在一起，如下程序代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Customer customer=new Customer();
customer.setName(“pansl”);
customer.setAge(80);
Query query=session.createQuery(“from Customer c where c.name=:name and c.age=:age ”);
query.setProperties(customer);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;setProperties()方法会自动将customer对象实例的属性值匹配到命名参数上，但是要求命名参数名称必须要与实体对象相应的属性同名。&lt;/p&gt;
&lt;h5 id=&quot;h5-5-1-5-setentity-&quot;&gt;&lt;a name=&quot;5.1.5、特殊的setEntity()方法&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;5.1.5、特殊的setEntity()方法&lt;/h5&gt;&lt;p&gt;它会把命名参数与一个持久化对象相关联，如下面代码所示：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;Customer customer=(Customer)session.load(Customer.class,”1”);
Query query=session.createQuery(“from Order order where order.customer=:customer ”);
query. setEntity(“customer”,customer);
List list=query.list();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面的代码会生成类似如下的SQL语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-mysql&quot;&gt;Select * from order where customer_ID=&amp;#39;1&amp;#39;;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;h2-u53C2u8003&quot;&gt;&lt;a name=&quot;参考&quot; class=&quot;reference-link&quot; href=&quot;#&quot;&gt;&lt;/a&gt;&lt;span class=&quot;header-link octicon octicon-link&quot;&gt;&lt;/span&gt;参考&lt;/h2&gt;&lt;p&gt;1、&lt;a href=&quot;https://xz.aliyun.com/t/10686#toc-0&quot;&gt;https://xz.aliyun.com/t/10686#toc-0&lt;/a&gt;&lt;br&gt;2、&lt;a href=&quot;https://b1ngz.github.io/java-sql-injection-note/&quot;&gt;https://b1ngz.github.io/java-sql-injection-note/&lt;/a&gt;&lt;br&gt;3、&lt;a href=&quot;https://zhuanlan.zhihu.com/p/134037462&quot;&gt;https://zhuanlan.zhihu.com/p/134037462&lt;/a&gt;&lt;br&gt;4、&lt;a href=&quot;https://zhuanlan.zhihu.com/p/42841510&quot;&gt;https://zhuanlan.zhihu.com/p/42841510&lt;/a&gt;&lt;br&gt;5、&lt;a href=&quot;https://developer.aliyun.com/article/271035#:~:text=%E5%AE%83%E4%BB%AC%E9%83%BD%E4%B8%93%E7%94%A8%E4%BA%8E%E5%8F%91%E9%80%81,%E5%B7%B2%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B%E7%9A%84%E8%B0%83%E7%94%A8%E3%80%82&amp;amp;text=Statement%E6%95%88%E7%8E%87%E4%BC%9A%E6%9B%B4%E9%AB%98%E4%B8%80%E7%82%B9%E3%80%82&quot;&gt;https://developer.aliyun.com/article/271035#:~:text=%E5%AE%83%E4%BB%AC%E9%83%BD%E4%B8%93%E7%94%A8%E4%BA%8E%E5%8F%91%E9%80%81,%E5%B7%B2%E5%AD%98%E5%82%A8%E8%BF%87%E7%A8%8B%E7%9A%84%E8%B0%83%E7%94%A8%E3%80%82&amp;amp;text=Statement%E6%95%88%E7%8E%87%E4%BC%9A%E6%9B%B4%E9%AB%98%E4%B8%80%E7%82%B9%E3%80%82&lt;/a&gt;&lt;br&gt;6、&lt;a href=&quot;https://www.cnblogs.com/zsh-blogs/p/10574381.html&quot;&gt;https://www.cnblogs.com/zsh-blogs/p/10574381.html&lt;/a&gt;&lt;br&gt;7、&lt;a href=&quot;https://zhuanlan.zhihu.com/p/42841510&quot;&gt;https://zhuanlan.zhihu.com/p/42841510&lt;/a&gt;&lt;br&gt;8、&lt;a href=&quot;https://c0d3p1ut0s.github.io/MyBatis%E6%A1%86%E6%9E%B6%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84SQL%E6%B3%A8%E5%85%A5/&quot;&gt;https://c0d3p1ut0s.github.io/MyBatis%E6%A1%86%E6%9E%B6%E4%B8%AD%E5%B8%B8%E8%A7%81%E7%9A%84SQL%E6%B3%A8%E5%85%A5/&lt;/a&gt;&lt;br&gt;9、&lt;a href=&quot;https://c0d3p1ut0s.github.io/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4MySQL-Prepared-Statement/&quot;&gt;https://c0d3p1ut0s.github.io/%E7%AE%80%E5%8D%95%E8%AF%B4%E8%AF%B4MySQL-Prepared-Statement/&lt;/a&gt;&lt;br&gt;10、&lt;a href=&quot;https://www.dineshonjava.com/hibernate/understanding-parameter-binding-and-sql/&quot;&gt;https://www.dineshonjava.com/hibernate/understanding-parameter-binding-and-sql/&lt;/a&gt;&lt;br&gt;11、&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/hibernate-query-language-hql-example-tutorial&quot;&gt;https://www.digitalocean.com/community/tutorials/hibernate-query-language-hql-example-tutorial&lt;/a&gt;&lt;br&gt;12、&lt;a href=&quot;https://blog.csdn.net/u011721501/article/details/43918203&quot;&gt;https://blog.csdn.net/u011721501/article/details/43918203&lt;/a&gt;&lt;br&gt;13、&lt;a href=&quot;https://www.sec-in.com/article/144&quot;&gt;Java代码审计之SQL注入——Hibernate框架-SecIN (sec-in.com)&lt;/a&gt;&lt;br&gt;14、&lt;a href=&quot;https://blog.csdn.net/qq_36908872/article/details/103523165&quot;&gt;https://blog.csdn.net/qq_36908872/article/details/103523165&lt;/a&gt;&lt;/p&gt;
</description><pubDate>Tue, 18 Oct 2022 23:33:37 +0800</pubDate></item></channel></rss>