<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Cookia&#39;s Notes</title>
  
  <subtitle>Have more fun</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://cookia.cc/"/>
  <updated>2018-03-11T14:20:43.127Z</updated>
  <id>http://cookia.cc/</id>
  
  <author>
    <name>Cookia</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>代码审计渗透测试（一） SQL注入</title>
    <link href="http://cookia.cc/2017/12/26/sql_injection/"/>
    <id>http://cookia.cc/2017/12/26/sql_injection/</id>
    <published>2017-12-26T13:33:40.000Z</published>
    <updated>2018-03-11T14:20:43.127Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>做为一枚纯正的甲方安全人员，代码审计是必备技能点。在实际工作中，代码审计无论是在安全测试中所占的投入比重，亦或是在发现产品/项目安全漏洞中的比例，都比黑盒渗透要大的多。因此，博主特意开辟了该代码审计系列博文，结合了博主在某厂实际工作中的工作经历和厂内大牛前辈们的经验，稍加提炼而成。<br>在正式开始专项之前，先简单介绍下“代码审计渗透测试”这个自创的新词：<br>一般来讲，Web安全测试主要分为<code>黑盒测试</code>和<code>白盒测试</code>:<br><code>黑盒测试</code>是指测试人员不清楚Web具体的架构和实现，通过模拟一个或多个攻击角色进行渗透测试，发现潜在的安全漏洞和风险，它不会泄露系统源码。<br><code>白盒测试</code>则需要开发人员提供相关的设计文档、源码、使用手册、业务逻辑等信息，对源代码直接进行安全分析，来寻找安全漏洞和可能存在的风险，它主要用于公司内部进行深度安全测试。代码审计是白盒测试常用的一种方法。<br><code>代码审计渗透测试</code>则是将黑盒渗透测试的思路用于代码审计的一种方法，博主将从漏洞介绍、漏洞原理、测试思路和测试方法四个方面来阐述TOP N的Web安全漏洞的代码审计渗透测试。</p></blockquote><p><img src="/assets/blogimg/security/security-1.jpg" width="100%"></p><a id="more"></a><h3 id="漏洞介绍"><a href="#漏洞介绍" class="headerlink" title="漏洞介绍"></a>漏洞介绍</h3><p>SQL注入漏洞是Web常见的漏洞，通过此漏洞可能用来拖库、获取Web管理员账号和密码、权限提升等攻击，是Web安全中最严重的漏洞之一。</p><blockquote><p>注意：本章节仅讨论<code>关系型</code>数据库，<code>不适用非关系型</code>数据库。</p></blockquote><h3 id="漏洞原理"><a href="#漏洞原理" class="headerlink" title="漏洞原理"></a>漏洞原理</h3><p>SQL注入(SQL Injection)，就是通过把SQL命令插入到<code>Web表单提交</code>或<code>页面请求</code>的字符串中，最终达到欺骗数据库服务器执行恶意的SQL命令,从而达到攻击的目的。<br>用户输入的内容，传递到服务端后没有做有效的过滤，后端拿到用户输入的不安全的内容后当做SQL命令直接执行，从而改变了原来的业务的SQL运行流程或者在执行了原有的SQL语句后，附加执行了用户的恶意SQL语句，导致数据库信息泄露或者权限提升。</p><blockquote><p>举个栗子：<br>username:<br>password:<br>前台需要输入用户名和密码。<br>后台的处理代码如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">username = getRequestName(<span class="string">"UserName"</span>);</div><div class="line">password = getRequestPassword(<span class="string">"UserPasswd"</span>);</div><div class="line">sql = <span class="string">"SELECT * FROM USER WHERE name = '"</span> + username +<span class="string">"' AND passwd = '"</span> + password + <span class="string">"'"</span>;</div></pre></td></tr></table></figure></p><p>这里后台拿到前端传参后没有做任何处理，直接拼接了SQL语句，这就很容易被SQL注入了：<br>username: admin’ or ‘1’ = ‘1<br>password: anything<br>这时候，后台构造的语句即为：<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">sql = "<span class="keyword">SELECT</span> * <span class="keyword">FROM</span> <span class="keyword">USER</span> <span class="keyword">WHERE</span> <span class="keyword">name</span> = <span class="string">'admin'</span> <span class="keyword">or</span> <span class="string">'1'</span> = <span class="string">'1'</span> <span class="keyword">AND</span> passwd = <span class="string">'anything'</span>;</div></pre></td></tr></table></figure></p><p>来分析这个SQL语句，你会发现，不管密码输入什么（anything），这条语句总会返回true，因为where xx or ‘1’ = ‘1’ 是恒成立的。因此用户不需要知道用户名和密码就能够成功登录到系统。</p></blockquote><p>从上面例子可以看出，用户可以构造出改变原本程序的运行逻辑的恶意代码，从而导致SQL注入。</p><p>更多SQL相关的知识详见：<a href="https://websec.ca/kb/sql_injection" target="_blank" rel="external">SQL_Injection</a></p><h3 id="测试思路"><a href="#测试思路" class="headerlink" title="测试思路"></a>测试思路</h3><p>渗透测试前，先要与开发人员进行沟通确认，找到存在用户输入并且需要操作数据库的地方，再去看是否进行了防SQL注入的安全机制，该安全机制是否能被绕过等。常见的比如使用<code>预编译</code>:</p><blockquote><p>PHP:可以使用<code>mysqli</code>、<code>PDO</code>实现预编译<br>Java:可以使用<code>preparestatement</code>预编译</p></blockquote><p>在SQL注入的测试中，仅仅通过黑盒渗透是远远不够的，原因如下:</p><ul><li>AppScan/AWVS无法获取到所有的业务报文，Burp可以获取较多的报文，但是注入用例太少，不能进行全面的覆盖，因此导致很多工具都没法进行全面的SQL注入渗透测试</li><li>渗透测试工具没法进行一些需要特定条件才能注入成功的操作，或者是正常场景不会出现的情况，容易产生遗漏</li></ul><p>因此针对SQL注入，强烈推荐使用本文<code>源码分析</code>为主，黑盒测试为辅。源码分析遵从以下规则：</p><ul><li>未使用预编译的，必须换为预编译，如果存在不能预编的场景，需要单独拿出来进行安全分析；</li><li>使用预编译的，必须使用占位符，不能针对sql拼接。</li></ul><h4 id="黑盒测试"><a href="#黑盒测试" class="headerlink" title="黑盒测试"></a>黑盒测试</h4><p>在测试前，通过与开交流或者源码源码分析，了解Web中使用的所有数据库名称及版本号，包括关系型数据库（MySQL、Oracle、SQLite等）,然后针对性测试，减少测试工作量。黑盒测试思路如下：</p><blockquote><p>1）Web漏洞扫描<br>利用Web漏洞扫描工具如AppScan、AWVS、Burp自动扫描，可以发现部分注入SQL注入漏洞，针对发现的漏洞“点”，在源码分析漏洞产生的原因，然后全面排查类似问题。</p><p>2）手工SQL注入<br>在Web界面中找到可能存在数据库操作的点，例如用户用户、数据查询、添加用户等场景，然后尝试手工测试，来发现比较隐蔽，以及工具难以覆盖的SQL注入漏洞。</p></blockquote><h4 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h4><p>通过分析源码，识别可能被绕过的SQL注入场景，例如绕过正则、关键字过滤、编码等，常见的SQL注入根因如下：</p><ul><li>直接拼接SQL语句，导致存在SQL注入</li><li>不正确使用预编译导致存在SQL注入</li><li>通过拼接，有过滤但过滤不全能被绕过导致SQL注入</li><li>第三方框架导致SQL注入（如Hibernate、iBatis……）</li><li>其它原因导致存在的SQL注入</li></ul><h3 id="测试方法"><a href="#测试方法" class="headerlink" title="测试方法"></a>测试方法</h3><p>Web漏洞扫描在<code>测试工具</code>中有详细介绍，因此本章节测试方法重点介绍手工SQL注入和Web源码分析SQL注入。</p><h4 id="非预编译导致的SQL注入"><a href="#非预编译导致的SQL注入" class="headerlink" title="非预编译导致的SQL注入"></a>非预编译导致的SQL注入</h4><p>大部分SQL注入漏洞的根因都是因为没有使用预编译，使用SQL语句拼接，导致用户构造的恶意语句改变了原有的SQL流程。测试方法如下：<br>1）通过手动搜索关键字分析SQL拼接场景是否存在漏洞，关键字如下：<br><strong>PHP关键字：<code>query</code> 、<code>mysql_query</code> 、<code>mysql_fetch_array</code> ……</strong><br><strong>Java关键字：<code>Statement</code> 、<code>.execute</code> 、<code>.executeQuery</code>、<code>jdbcTemplate</code>、<code>queryForInt</code>、<code>queryForObject</code>、<code>queryForMap</code>、<code>getConnection</code></strong><br>2）分析SQL执行的场景是否使用了预编译，以java为例，可以通过搜索关键字<code>queryForInt</code>搜索到的代码假设如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> <span class="keyword">static</span> String STR_QUERY_FILE = <span class="string">"SELECT COUNT(1) FROM TBL_XXX WHERE XXX_FILENAME = '%s'"</span>;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> boolen <span class="title">isXXXFileUsed</span><span class="params">(String strFileName)</span></span>&#123;</div><div class="line">    String strSql = String.format(STR_QUERY_FILE, strFileName);</div><div class="line">    <span class="keyword">if</span>(Constant.NUMBER_ZERO &lt; getSimpleJdbcTemplate().queryForInt(strSql))&#123;</div><div class="line">    ......</div><div class="line">    &#125;</div><div class="line">    ......</div><div class="line">    <span class="keyword">return</span> flase;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p><p>STR_QUERY_FILE为SQL语句查询字符串，strFileName为客户端传参，也就是该参数由用户直接输入，即用户可控，这里并没有进行过滤，也没有进行预编译，直接使用format进行字符串拼接后执行SQL，因此此处是存在SQL注入漏洞的。<br>漏洞利用Exploit如下：<br><figure class="highlight sql"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">a.dat; <span class="keyword">delete</span> <span class="keyword">from</span> <span class="keyword">user</span>;</div></pre></td></tr></table></figure></p><h4 id="错误的预编译导致的SQL注入"><a href="#错误的预编译导致的SQL注入" class="headerlink" title="错误的预编译导致的SQL注入"></a>错误的预编译导致的SQL注入</h4><p>有时候开发人员虽然使用了预编译，但是错误的预编译仍然是存在SQL漏洞的，因此代码审计时需要分析PreparedStatement时是否使用占用符，测试方法如下：<br>1）通过搜索关键字，先找到使用预编译的场景，关键字如下：<br><strong>PHP关键字：<code>prepare</code> 、<code>execute</code></strong><br><strong>Java关键字：<code>preparedStatement</code></strong><br>2）分析代码是否存在漏洞，预编译之前的参数绑定应该使用占位符，不应该直接使用拼接。例如：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">strSql = <span class="string">"SELECT uu_name from table_appmanage "</span>;</div><div class="line"><span class="keyword">if</span>(uu_key != <span class="keyword">null</span>)&#123;</div><div class="line">    strSql.append(<span class="string">"where key = '"</span> + uu_k + <span class="string">"'"</span>);</div><div class="line">&#125;</div><div class="line">sql = strSql.toString();</div><div class="line">ps = conn.preparedStatement(sql);</div><div class="line">re = ps.executeQuery();</div><div class="line">.....</div></pre></td></tr></table></figure></p><p>这里虽然使用了preparedStatement预编译，但是在预编译之前，append拼接参数时已经被污染，所以这里也是无法防御SQL注入的。正确的方法应该如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">strSql = <span class="string">"SELECT uu_name from table_appmanage where key = ? "</span>);</div><div class="line">PreparedStatement ps = conn.preparedStatement(sreSql);</div><div class="line">ps.setString(<span class="number">1</span>, uu_key);</div><div class="line">re = ps.executeQuery();</div></pre></td></tr></table></figure></p><h4 id="过滤不完整导致SQL注入"><a href="#过滤不完整导致SQL注入" class="headerlink" title="过滤不完整导致SQL注入"></a>过滤不完整导致SQL注入</h4><p>在有些场景没办法使用预编译。比如建表的SQL语句没法使用参数绑定+预编译来放回SQL注入，这个时候就需要进行SQL动态拼接，而防止SQL注入就需要进行特殊字符的过滤，一般大家都喜欢使用黑名单，而黑名单却是最容易绕过，无法达到防护的目的。这种情况的测试方法如下：<br>1）在源码中搜索如下关键字，找到相关的代码：<br><strong>PHP关键字：<code>query</code> 、<code>mysql_query</code>、<code>mysql_fetch_array</code> ······</strong><br><strong>Java关键字：<code>statement</code>、<code>execute</code>、<code>jdbcTemplate</code>、<code>queryForInt</code>、<code>queryForObject</code>、<code>queryForMap</code>、<code>executeQuery</code>、<code>getConnection</code> ······</strong><br>2）分析测试是否存在绕过的风险，例如（PHP）：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">$sid = strtolower($_REQUEST[id]);</div><div class="line">    $key1 = <span class="keyword">array</span>(<span class="string">"="</span>, <span class="string">"order"</span>, <span class="string">"or"</span>, <span class="string">"xor"</span>, <span class="string">"&gt;"</span>, <span class="string">"&lt;"</span>, <span class="string">"null"</span>);</div><div class="line">    $id = str_replace($key1,<span class="string">""</span>, $sid);</div><div class="line">    $conn = mysql_connect($servername, $dbusername, $dbpassword) <span class="keyword">or</span> <span class="keyword">die</span>(<span class="string">"connect db failed"</span>);</div><div class="line">    mysql_select_db($dbname, $conn);</div><div class="line">    mysql_query(<span class="string">'set names utf8'</span>);</div><div class="line">    $sql = <span class="string">"select * from article where articleid = $id"</span>;</div><div class="line">    $result = mysql_query($sql, $conn);</div><div class="line">    $row = mysql_fetch_array($result);</div></pre></td></tr></table></figure></p><p>这里使用的是MYSQL数据库，没有使用参数绑定加预编译的形式，id参数来源于客户端请求，开发人员意识到存在SQL注入安全风险，进行SQL执行前使用了str_replace进行了字符过滤，将$key1中的字符替换为空，实际上这样过滤远远不够，使用union就可以轻松绕过，漏洞利用可以参考：<br><figure class="highlight php"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/index.php?id=<span class="number">-1</span> union select <span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span></div></pre></td></tr></table></figure></p><h4 id="Hibernate导致的SQL注入-仅存在于java"><a href="#Hibernate导致的SQL注入-仅存在于java" class="headerlink" title="Hibernate导致的SQL注入(仅存在于java)"></a>Hibernate导致的SQL注入(<code>仅存在于java</code>)</h4><p>Hibernate是一个开源的java框架，它对JDBC进行了非常轻量级的对象封装，它可以生成SQL语句，自动执行，使得java程序员可以自由的使用OOP思想来操纵数据库，因此深受欢迎。<br>Hibernate本身支持预编译，但是如果使用动态拼接，则也会存在SQL注入风险，测试方法如下：<br>1）判断web中是否使用了Hibernate，搜索如下关键字：<br><strong>Hibernate关键字：<code>org.hibernate</code>  </strong><br>2）分析是否为SQL拼接，搜索一下关键字分析相关代码是否存在拼接：<br><strong>关键字：<code>.createQuery</code></strong><br>例如：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">String username = request.getParameter(<span class="string">"username"</span>);</div><div class="line">String str = <span class="string">"from user_table where name = "</span> + username;</div><div class="line">Query q = session.createQuery(str);</div></pre></td></tr></table></figure></p><p>代码中通过Hibernate来查询数据库，username为外部输入参数，然后与sql动态拼接，因此存在SQL注入漏洞。</p><p>安全的使用方法应该是<code>使用占位符进行参数绑定</code>，再使用<code>预编译</code>：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">String username = request.getParameter(<span class="string">"username"</span>);</div><div class="line">String str = <span class="string">"from user_table where name = ?"</span>;</div><div class="line">Query q = session.createQuery(str);</div><div class="line">q.setString(<span class="number">0</span>, username);</div></pre></td></tr></table></figure></p><h4 id="iBatis-myBatis导致的SQL注入-仅存在于java"><a href="#iBatis-myBatis导致的SQL注入-仅存在于java" class="headerlink" title="iBatis/myBatis导致的SQL注入(仅存在于java)"></a>iBatis/myBatis导致的SQL注入(<code>仅存在于java</code>)</h4><p>iBatis(后被谷歌托管，改名为myBatis)是用于使用方便的数据访问工具，也主要作为数据持久层，与ORM(Hibernate)类似。i/myBatis中#是占位符，$是字符串拼接，所以尽量使用#可以避免SQL注入，而$则会存在风险，测试方法如下：<br>1）判断web中是否使用了iBatis/myBatis,在源码中搜索以下关键字，如果存在说明项目中使用了iBatis/myBatis，关键字如下：<br><strong>iBatis关键字：<code>import com.ibatis</code></strong><br><strong>myBatis关键字：<code>import org.mybatis</code></strong><br>2）判断SQL调用时，是否使用了$拼接。例如：<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">&lt;select id=<span class="string">"testSQL"</span> parameterClass=<span class="string">"com.it.users"</span> resultClass=<span class="string">"users"</span>&gt;</div><div class="line">SELECT * FROM users WHERE username = <span class="string">'$username$'</span></div><div class="line">&lt;/select&gt;</div></pre></td></tr></table></figure></p><p>这里使用的就是$username$，进行了SQL拼接，username被用户恶意输入则造成了SQL漏洞。<br>正确的使用应该是：<br><figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">&lt;select id=<span class="string">"testSQL"</span> parameterClass=<span class="string">"com.it.users"</span> resultClass=<span class="string">"users"</span>&gt;</div><div class="line">SELECT * FROM users WHERE username = #username#</div><div class="line">&lt;/select&gt;</div></pre></td></tr></table></figure></p><h4 id="其他原因导致的SQL注入"><a href="#其他原因导致的SQL注入" class="headerlink" title="其他原因导致的SQL注入"></a>其他原因导致的SQL注入</h4><p>PHP的SQL注入更加灵活复杂，也存在上面类似的ORM框架，同理也就可能存在SQL注入风险，但是往往结果框架的包装后，就很难轻易的识别出这些安全风险，给白盒渗透测试带来困难。除了上述因素外，还有其他场景和因素导致SQL注入：<br>1）字符编码导致SQL宽字节注入<br>2）不正确的使用安全函数导致的SQL注入，尤其是PHP弱语言最容易发生<br>3）代码逻辑导致的SQL注入<br>尤其是代码逻辑，这个需要深入熟悉业务，也需要有较强的逻辑思维能力。</p><blockquote><p><strong><em>PS：</em></strong><br>1)产品安全测试过程中测试量大，参数多，因此最高速有效的测试方法就是基于正常报文添加单双引号，然后查看数据库日志。当然如果你非常熟悉手工注入也可以直接构造出SQL来证明是存在漏洞的。<br>2)在实际排查的过程中，使用关键字搜索，大多数会得到很多结果，如果一个一个的去分析调用，参数是否可控，工作量相当大，并且很容易产生漏洞。这时，就需要开发人员先将能使用预编译的地方使用参数绑定+预编译，然后再去详细分析不能使用预编译的地方进行定点分析，提高开发和测试效率。</p></blockquote>]]></content>
    
    <summary type="html">
    
      &lt;blockquote&gt;
&lt;p&gt;做为一枚纯正的甲方安全人员，代码审计是必备技能点。在实际工作中，代码审计无论是在安全测试中所占的投入比重，亦或是在发现产品/项目安全漏洞中的比例，都比黑盒渗透要大的多。因此，博主特意开辟了该代码审计系列博文，结合了博主在某厂实际工作中的工作经历和厂内大牛前辈们的经验，稍加提炼而成。&lt;br&gt;在正式开始专项之前，先简单介绍下“代码审计渗透测试”这个自创的新词：&lt;br&gt;一般来讲，Web安全测试主要分为&lt;code&gt;黑盒测试&lt;/code&gt;和&lt;code&gt;白盒测试&lt;/code&gt;:&lt;br&gt;&lt;code&gt;黑盒测试&lt;/code&gt;是指测试人员不清楚Web具体的架构和实现，通过模拟一个或多个攻击角色进行渗透测试，发现潜在的安全漏洞和风险，它不会泄露系统源码。&lt;br&gt;&lt;code&gt;白盒测试&lt;/code&gt;则需要开发人员提供相关的设计文档、源码、使用手册、业务逻辑等信息，对源代码直接进行安全分析，来寻找安全漏洞和可能存在的风险，它主要用于公司内部进行深度安全测试。代码审计是白盒测试常用的一种方法。&lt;br&gt;&lt;code&gt;代码审计渗透测试&lt;/code&gt;则是将黑盒渗透测试的思路用于代码审计的一种方法，博主将从漏洞介绍、漏洞原理、测试思路和测试方法四个方面来阐述TOP N的Web安全漏洞的代码审计渗透测试。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/assets/blogimg/security/security-1.jpg&quot; width=&quot;100%&quot;&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="安全" scheme="http://cookia.cc/categories/%E5%AE%89%E5%85%A8/"/>
    
    
      <category term="代码审计" scheme="http://cookia.cc/tags/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/"/>
    
      <category term="白盒测试" scheme="http://cookia.cc/tags/%E7%99%BD%E7%9B%92%E6%B5%8B%E8%AF%95/"/>
    
      <category term="渗透测试" scheme="http://cookia.cc/tags/%E6%B8%97%E9%80%8F%E6%B5%8B%E8%AF%95/"/>
    
      <category term="SQL注入" scheme="http://cookia.cc/tags/SQL%E6%B3%A8%E5%85%A5/"/>
    
  </entry>
  
  <entry>
    <title>一波太多折</title>
    <link href="http://cookia.cc/2017/10/09/30/"/>
    <id>http://cookia.cc/2017/10/09/30/</id>
    <published>2017-10-09T14:44:40.000Z</published>
    <updated>2017-10-10T15:13:00.953Z</updated>
    
    <content type="html"><![CDATA[<p><img src="/assets/blogimg/notes/notes-3.jpg" width="50%"></p><h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h3><p>10月7日下午4点58分，十堰到武汉动车。10月8日凌晨6点多武汉到广州的票（虽然后来换票了）。<br>10月7日、10月8日，十堰到武汉的车都无票。</p><a id="more"></a><blockquote><p>关于时间节点，描述精确的要么是我看过表，要么是电话记录，要么是滴滴订单。不确定的，描述中会使用x分左右。</p></blockquote><h3 id="事情是这样的"><a href="#事情是这样的" class="headerlink" title="事情是这样的"></a>事情是这样的</h3><p>10月7日中午参加完婚礼，时间1点50，一行四个人闲来无事，买了4张票去看羞羞的铁拳，2点10分到3点50多。<br>看完出来上厕所等电梯拿行李等，到马路边叫了滴滴等，此时4点15分，动车开车时间是4点58分。<br>此时找身份证准备待会儿取票用的时候才发现钱包不见了。赶紧翻包翻箱子，没有找到。</p><p>4点17分左右，滴滴来了，让另外俩小伙伴先走，我和妹子再找找。他们走后，我直接跑到结婚酒店的前台问，告知婚礼的负责在4楼前台，迈着刚爬了青城山和武当山两座大山的酸腿飞奔上四楼，告知没有人捡到，让我自己去5楼大厅看看，此时已经明白基本无望了，还是飞奔而去，果然都收拾干净了，再飞奔下一楼。<br>看时间4点21了。来不及了，错过了这趟车，今天就没有车回武汉，明天也就回不了深圳，明天也没有车去武汉的。。决定先去火车站看能不能搞到临时证明，先去武汉再说。</p><p>4点23分，滴滴接单。</p><p>4点24分，司机打来电话。</p><p>4点27分，上车。</p><p>4点45分，快到车站的时候，堵车，和妹子商量，我先去跑过去搞证明，取票。</p><p>4点46分，拿了她的身份证下车狂奔。此时离开车还有12分，一切顺利就还来得及，只能这么安慰自己。</p><p>你以为老天的考验就这样了？太单纯了。我当时也是。太单纯了。</p><p>4点59分左右，到达人工售票窗口，问清了哪里办临时证件，跑过去，有人在办，窃喜，再一问，告知需要一张照片。WTF，这什么卵规定，我TM现在去哪里弄，工作人员一指，马路对面，我一看时间，4点50了，马路对面？你逗我？目测一里多路，还得找照相馆，还得照，还得洗出来，这怎么可能来得及？感觉世界已经崩塌，自己是走不了了，赶紧去自动取票机帮妹子取了票，等她来了让她先走，能走一个是一个。</p><p>4点51分，妹子一个人拖着箱子，背着一个包，提着包，走过来了，看我在这里等，估计以为都搞好了，结果我拿出一张票给她，你先走，我是走不了了。她愣了一下，也急了，最后问清楚了，说再去说了看看，我说我说过了，不让，必须要照片。<br>最后，4点52分，又去了窗口，这次我们一起说，更显急迫，工作人员 终于答应了，内心狂喜。以为运气来了，结果发现自己还是太单纯。</p><p>4点53分，办好了临时证明，让妹子带着行李先进站了，因为订单号在她手机上，无证取票要订单号，于是我拿着她的手机狂奔去人工取票。三个窗口开着，直接去第一个，插队问，回答她这里办不了，去另一个。到另一个，正在办理，问了两遍不理我。我去第三个，办不了，只能第二个。又跑去第二个，再问，还是不回答，看着她不忙不急的办理，不经历的很难理解当时是一种是心情。</p><p>4点55分，还没办完，忍不住了，再次问能不能先帮我搞下，我58分车。“我搞了半天。总不能取消掉吧，你等着！”我当时竟然笑了。然后看着她又点了会儿，拿出4个身份证一个一个刷，一个一个出票，后面人都看着我，眼里满是同情。第一个买票的大爷，也有点不好意思，抬头看了看我，又看了看售票员，最后低头没说话。我笑着摇了摇头。</p><p>4点57分，到我了，本来已经绝望了，但是票还是得取，20秒取票走人，不忘说一句谢谢。</p><p>再晚一分钟，票过了58分就取不出来了。</p><p>这时候，其实我已经可以放弃了。因为按照常理已经停止检票，就算让你进去了，也只能看着车走了。</p><p>但是我还是疯狂的跑进去了，虽然内心真真正正的已经绝望。</p><p>安检，因为没有行李，所以很快</p><p>4点58到检票处，看到妹子在检票口叫我赶紧，愣了一下，边想着怎么还没停止检票，边飞奔过去。</p><p>检票进去后，看到了之前的俩小伙伴，很是惊讶，一问，他们都说，我运气好，动车起点站晚点的，第一次遇到。不然，我这肯定是赶不上了。</p><p>我这运气，到底是好，还是不好。一言难尽。</p><p>进去后，才发现本来已经酸疼的腿，这一路上竟然一点感觉都没有，直到在车上坐下来才瑟瑟发抖。。。</p><blockquote><p>什么？损失？钱不多，就几十块人民币加几十块港币，记起来200不到。但是身份证，4张银行卡，1张社保卡。。。后续会有多麻烦。</p><p>教训：以后还是得放些钱在钱包，只有钱包有钱了，平常才会记得时时看看，才会重视。不然，这次没钱，连什么时候掉的都想不起来。。</p></blockquote><p><br></p><p>所以啊，人生呢<br>不迈出第一步，你永远不知道下一步在哪里。<br>不走到最后一步，你永远不知道结局是什么。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;img src=&quot;/assets/blogimg/notes/notes-3.jpg&quot; width=&quot;50%&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h3&gt;&lt;p&gt;10月7日下午4点58分，十堰到武汉动车。10月8日凌晨6点多武汉到广州的票（虽然后来换票了）。&lt;br&gt;10月7日、10月8日，十堰到武汉的车都无票。&lt;/p&gt;
    
    </summary>
    
      <category term="随笔" scheme="http://cookia.cc/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
      <category term="经历" scheme="http://cookia.cc/tags/%E7%BB%8F%E5%8E%86/"/>
    
  </entry>
  
  <entry>
    <title>Redos攻击原理与检测防御</title>
    <link href="http://cookia.cc/2017/09/13/redos/"/>
    <id>http://cookia.cc/2017/09/13/redos/</id>
    <published>2017-09-13T14:38:40.000Z</published>
    <updated>2017-12-22T14:41:55.930Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>同名博客发表于菊厂3ms<br><!-- <img src="/assets/blogimg/notes/notes-3.jpg" width = "50%" /> --></p></blockquote><p><strong>Regular expression Denial of Service (ReDoS)是一种利用程序实现时采用了不安全的正则表达式，从而构造特定输入引起DOS拒绝服务的一种攻击手段。</strong></p><p>在正式讨论ReDos之前，先来介绍一下预备知识。</p><h2 id="Regex与DFA、NFA"><a href="#Regex与DFA、NFA" class="headerlink" title="Regex与DFA、NFA"></a>Regex与DFA、NFA</h2><blockquote><p>不想看原理可以直接跳过去看例子，部分人可秒懂</p></blockquote><p>正则表达式，又称规则表达式，英文名为Regular Expression，在代码中常简写为regex、regexp或RE，是计算机科学的一个概念。</p><p>正则表通常被用来检索、替换那些符合某个模式(规则)的文本。</p><p>正则表达式是对字符串（包括普通字符（例如，a 到 z 之间的字母）和特殊字符（称为“元字符”））操作的一种逻辑公式，就是用事先定义好的一些特定字符、及这些特定字符的组合，组成一个“规则字符串”，这个“规则字符串”用来表达对字符串的一种过滤逻辑。</p><p>正则表达式是一种文本模式，模式描述在搜索文本时要匹配的一个或多个字符串。</p><p>DFA 引擎在线性时状态下执行，因为它们不要求回溯（并因此它们永远不测试相同的字符两次）。<br>DFA 引擎还可以确保匹配最长的可能的字符串。<br>但是，因为 DFA 引擎只包含有限的状态，所以它不能匹配具有反向引用的模式；并且因为它不构造显示扩展，所以它不可以捕获子表达式。<br><a id="more"></a><br>传统的 NFA 引擎运行所谓的“贪婪的”匹配回溯算法，以指定顺序测试正则表达式的所有可能的扩展并接受第一个匹配项。<br>因为传统的 NFA 构造正则表达式的特定扩展以获得成功的匹配，所以它可以捕获子表达式匹配和匹配的反向引用。<br>但是，因为传统的 NFA 回溯，所以它可以访问完全相同的状态多次（如果通过不同的路径到达该状态）。<br>因此，在最坏情况下，它的执行速度可能非常慢。因为传统的 NFA 接受它找到的第一个匹配，所以它还可能会导致其他（可能更长）匹配未被发现。</p><p>POSIX NFA 引擎与传统的 NFA 引擎类似。<br>不同的一点在于：在它们可以确保已找到了可能的最长的匹配之前，它们将继续回溯。<br>因此，POSIX NFA 引擎的速度慢于传统的 NFA 引擎；并且在使用 POSIX NFA 时，您恐怕不会愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索，而非较长的匹配搜索。</p><ul><li>使用DFA引擎的程序主要有：awk,egrep,flex,lex,MySQL,Procmail等；</li><li>使用传统型NFA引擎的程序主要有：GNU Emacs,Java,ergp,less,more,.NET语言,PCRE library,Perl,PHP,Python,Ruby,sed,vi；</li><li>使用POSIX NFA引擎的程序主要有：mawk,Mortice Kern Systems’ utilities,GNU Emacs(使用时可以明确指定)；</li><li>也有使用DFA/NFA混合的引擎：GNU awk,GNU grep/egrep,Tcl。</li></ul><p><strong>下面用实例来说明正则匹配时，NFA与DFA引擎的区别：</strong><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">字符串： hello regextest</div><div class="line">正则表达式：  \reg(axtest|extext|extest)</div></pre></td></tr></table></figure></p><p><code>DFA</code>：拿着字符串文本去匹配正则表达式。<br>hello没有正则匹配的，去掉，reg匹配上了，继续；exte和第二、三分支匹配，继续；st和第三分支匹配，至此，regextest匹配成功，结束。过程中字符串只遍历了一次。</p><p><code>NFA</code>：拿着正则表达式去对比字符串文本。<br>r-&gt;淘汰hello，匹配到r，e-&gt;e，g-&gt;g，a-&gt;e失败，回溯到上一个匹配的g，匹配下一个正则，e-&gt;e，x-&gt;x，t-&gt;t，e-&gt;e，x-&gt;s失败，回溯到上一个匹配的e，匹配下一个正则，s-&gt;s，t-&gt;t，匹配成功，结束。过程中字符串遍历了多次。</p><h3 id="DOS"><a href="#DOS" class="headerlink" title="DOS"></a>DOS</h3><p><strong>DOS攻击</strong>这里引用段子嘎的介绍：<br>DoS（Denial of Service，拒绝服务）是一种网络攻击手段，通过大量合法的请求占用大量网络资源，以达到瘫痪网络的目的。<br>形象一点的比喻是，你开了一家小面馆，黑客派了几个广场的大爷大妈涌入你的店里坐着吹空调，也不消费就霸着场子，导致其他顾客根本无法进店消费。<br>想详细了解可自行去查资料。</p><p><br></p><h2 id="下面开始介绍本文重点：ReDos"><a href="#下面开始介绍本文重点：ReDos" class="headerlink" title="下面开始介绍本文重点：ReDos"></a>下面开始介绍本文重点：ReDos</h2><h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p>本文主要介绍使用NFA引擎的程序语言，使用DFA引擎的程序不存在ReDos。因为NFA引擎的回溯机制，导致了当字符串文本与正则表达式不匹配时，所花费的时间要比匹配时长的多。<br>简单点说，确定匹配成功就不做了，但是要确定匹配失败，则需要与所有可能的路径进行对比匹配，都证明匹配不了，才能确定匹配失败。</p><p>此时，如果使用简单的非分组正则表达式来进行匹配，也不会引起问题，例如：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">^\d+$</div></pre></td></tr></table></figure><ul><li><p>1）23x<br>23,<code>x</code>　　2,<code>3x</code>    　　<code>23x</code><br>标粗部分为确认不匹配的部分，第一次遇到不匹配时回溯到上一个继续进行匹配，共<code>3</code>次</p></li><li><p>2）123x<br>123,<code>x</code>　　12,<code>3x</code>　　1,<code>23x</code>　　<code>123x</code><br>标粗部分为确认不匹配的部分，第一次遇到不匹配时回溯到上一个继续进行匹配，共<code>4</code>次</p></li></ul><p>此时呈<code>线性</code>增长。</p><p>但是，如果使用重复性分组正则表达式来进行匹配，则可能引起问题，例如：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">^\(d+)+$</div></pre></td></tr></table></figure></p><ul><li><p>1）23x<br>23,<code>x</code>　　2,3,<code>x</code>　　2,<code>3x</code>    　　<code>23x</code><br>标粗部分为确认不匹配的部分，迭代多次才能确认原字符串不匹配，总共需要<code>2^2 = 4</code>次</p></li><li><p>2）123x<br>123,<code>x</code>　　12,3,<code>x</code>　　12,<code>3x</code>　　1,23,<code>x</code>　　1,2,3,<code>x</code>　　1,2,<code>3x</code>　　1,<code>23x</code>　　<code>123x</code><br>标粗部分为确认不匹配的部分，迭代多次才能确认原字符串不匹配，总共需要<code>2^3 = 8</code>次</p></li></ul><p>此时呈<code>指数</code>增长。</p><p><br></p><h3 id="验证"><a href="#验证" class="headerlink" title="验证"></a>验证</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># coding:utf-8</span></div><div class="line"></div><div class="line"><span class="keyword">import</span> time</div><div class="line"><span class="keyword">import</span> re</div><div class="line"></div><div class="line">strs = (</div><div class="line">    <span class="string">'1234567890x'</span>,</div><div class="line">    <span class="string">'12345678901234567890x'</span>,</div><div class="line">    <span class="string">'1234567890123456789012345x'</span>,</div><div class="line">    <span class="string">'12345678901234567890123456x'</span>,</div><div class="line">    <span class="string">'123456789012345678901234567x'</span>,</div><div class="line">    <span class="string">'1234567890123456789012345678x'</span>,</div><div class="line">    <span class="string">'12345678901234567890123456789x'</span></div><div class="line">)</div><div class="line">regex = <span class="string">'^(\d+)+$'</span></div><div class="line"></div><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">fun</span><span class="params">(strs, regex)</span>:</span></div><div class="line">    t1 = time.time()</div><div class="line">    result = re.compile(regex).match(strs)</div><div class="line">    t2 = time.time()</div><div class="line">    print(<span class="string">"%s : %s : %.2f"</span> % (strs, str(result), (t2 - t1)))</div><div class="line"></div><div class="line"><span class="keyword">for</span> s <span class="keyword">in</span> strs:</div><div class="line">    fun(s, regex)</div></pre></td></tr></table></figure><p>运行结果：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">C:\Python\Python36\python.exe D:/python/get_hi3ms_user_files/redos/redos.py</div><div class="line">1234567890x : None : 0.00</div><div class="line">12345678901234567890x : None : 0.09</div><div class="line">1234567890123456789012345x : None : 2.95</div><div class="line">12345678901234567890123456x : None : 5.92</div><div class="line">123456789012345678901234567x : None : 12.51</div><div class="line">1234567890123456789012345678x : None : 24.68</div><div class="line">12345678901234567890123456789x : None : 52.39</div><div class="line"></div><div class="line">Process finished with exit code 0</div></pre></td></tr></table></figure></p><p>可以看出每增加一位，其运行时间呈现<strong>指数</strong>增长。</p><p>再来查看运行时的CPU占用，测试机子为4核电脑，单进程跑，CPU25%，单核占满了。<br><img src="/assets/blogimg/tech/tech-1.png"></p><p>同时运行4个程序就能跑满100%CPU，可造成拒绝服务。<br><img src="/assets/blogimg/tech/tech-2.png"></p><h3 id="影响"><a href="#影响" class="headerlink" title="影响"></a>影响</h3><p>容易引起ReDos的正则表达式主要有两类：<br>1、    包含具有自我重复的重复性分组的正则，例如：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">^(\d+)+$</div><div class="line">^(\d*)*$</div><div class="line">^(\d+)*$</div><div class="line">^(\d+|\s+)*$</div><div class="line">…</div></pre></td></tr></table></figure></p><p>2、    包含替换的重复性分组，例如：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">^(\d|\d|\d)+$</div><div class="line">^(\d|\d?)+$</div><div class="line">…</div></pre></td></tr></table></figure></p><p>目前已经在使用的，甚至是一些官方提供的正则表达式，也可能存在缺陷：</p><p>1、    <a href="（http://regexlib.com/REDetails.aspx?regexp_id=1757&amp;AspxAutoDetectCookieSupport=1）">正则表达式库网站中，提供的专门用于验证电子邮件的正则</a><br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">/^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@)&#123;1&#125;[a-z0-9]+[.]&#123;1&#125;(([a-z]&#123;2,3&#125;)|([a-z]&#123;2,3&#125;[.]&#123;1&#125;[a-z]&#123;2,3&#125;))$/</div></pre></td></tr></table></figure></p><p>输入：aaaaaaaaaaaaaaaaaaaaaaaa!</p><p>2、    <a href="https://www.owasp.org/index.php/OWASP_Validation_Regex_Repository" target="_blank" rel="external">OWASP验证正则表达式库</a>，这也是一个有缺陷的正则：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">^(([a-z])+.)+[A-Z]([a-z])+$</div></pre></td></tr></table></figure></p><p>输入：aaaaaaaaaaaaaaaaaaaaaaaa!</p><p>3、    常用的：<br>多个邮箱地址验证<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">^[a-zA-Z]+(([\&apos;\,\.\-][a-zA-Z ])?[a-zA-Z]*)*\s+&amp;lt;(\w[-._\w]*\w@\w[-._\w]*\w\.\w&#123;2,3&#125;)&amp;gt;$|^(\w[-._\w]*\w@\w[-._\w]*\w\.\w&#123;2,3&#125;)$</div></pre></td></tr></table></figure></p><p>输入: aaaaaaaaaaaaaaaaaaaaaaaa!</p><p>复数验证<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">^\d*[0-9](|.\d*[0-9]|)*$</div></pre></td></tr></table></figure></p><p>输入: 1111111111111111111111111!</p><p>模式匹配<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">^([a-z0-9]+([\-a-z0-9]*[a-z0-9]+)?\.)&#123;0,&#125;([a-z0-9]+([\-a-z0-9]*[a-z0-9]+)?)&#123;1,63&#125;(\.[a-z0-9]&#123;2,7&#125;)+$</div></pre></td></tr></table></figure></p><p>输入: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!</p><p>另外，攻击者也可能通过输入来自己构造缺陷正则，从而发起攻击：<br>例如：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">String userName = textBox1.Text;</div><div class="line">String password = textBox2.Text;</div><div class="line">Regex testPassword = <span class="keyword">new</span> Regex(userName);</div><div class="line">match match = testPassword.Match(password);</div></pre></td></tr></table></figure></p><p>此时，攻击者输入：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">Userame：^(( [az])+.)+ [AZ]([az])+$</div><div class="line">Password：aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa！</div></pre></td></tr></table></figure></p><p>则会引起ReDos.</p><h3 id="风险因素"><a href="#风险因素" class="headerlink" title="风险因素"></a>风险因素</h3><p><img src="/assets/blogimg/tech/tech-3.png"></p><p>在web的每一层都包含有正则表达式，也就是每一层都会存在有缺陷的正则风险。<br>攻击者能够攻击Web浏览器（PC端或者移动端）、WAF、数据库或者是Web服务器。</p><h3 id="检测"><a href="#检测" class="headerlink" title="检测"></a>检测</h3><p>其实理想的方法是在代码编译时用一个正则去查找匹配存在缺陷的正则表达式，然而搜索了一下，没有找到这种有效的正则。目前比较好的检测手段主要分两种。</p><ul><li>一是静态代码工具分析，通过抓取代码中的正则去匹配已知的存在缺陷的特征库，重点需要检测存在分组和重复的正则，这种方法的准确率主要依赖于特征库的质量。</li><li>二是通过模糊测试去程序中进行检测。在使用了正则的地方不断使用多种字符串去进行输入匹配，记录下引擎在判断是否匹配时花费的时间，时间过长则很有可能存在不安全的正则。这种方法依赖于构造的字符串是否够全面。</li></ul><h3 id="防御"><a href="#防御" class="headerlink" title="防御"></a>防御</h3><p>目前主要的防御手段主要还是在程序中避免出现不安全的正则：</p><ul><li>1、    在编写正则的时候，尽量不要使用过于复杂的正则，越复杂越容易有缺陷，且越不容易进行全面的测试；</li><li>2、    编写正则的时候，尽量减少分组的使用量，使用的越多出现缺陷的可能性越大</li><li>3、    避免动态构造正则（即new Regex(…)），如果需要构造，也保证不要使用用户的输入来进行动态构造。</li><li>4、    严格限制用户输入的长度限制。</li></ul><p>服务端可以进行性能监控，暂时还没法进行有效的防御。</p><p><br><br><br></p><p>参考链接：<br><a href="https://msdn.microsoft.com/zh-cn/magazine/ff646973.aspx" target="_blank" rel="external">https://msdn.microsoft.com/zh-cn/magazine/ff646973.aspx</a><br><a href="https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS" target="_blank" rel="external">https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS</a><br><a href="https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215?fr=aladdin" target="_blank" rel="external">https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215?fr=aladdin</a><br><a href="http://www.freebuf.com/articles/network/124422.html" target="_blank" rel="external">http://www.freebuf.com/articles/network/124422.html</a></p>]]></content>
    
    <summary type="html">
    
      &lt;blockquote&gt;
&lt;p&gt;同名博客发表于菊厂3ms&lt;br&gt;&lt;!-- &lt;img src=&quot;/assets/blogimg/notes/notes-3.jpg&quot; width = &quot;50%&quot; /&gt; --&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Regular expression Denial of Service (ReDoS)是一种利用程序实现时采用了不安全的正则表达式，从而构造特定输入引起DOS拒绝服务的一种攻击手段。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在正式讨论ReDos之前，先来介绍一下预备知识。&lt;/p&gt;
&lt;h2 id=&quot;Regex与DFA、NFA&quot;&gt;&lt;a href=&quot;#Regex与DFA、NFA&quot; class=&quot;headerlink&quot; title=&quot;Regex与DFA、NFA&quot;&gt;&lt;/a&gt;Regex与DFA、NFA&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;不想看原理可以直接跳过去看例子，部分人可秒懂&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;正则表达式，又称规则表达式，英文名为Regular Expression，在代码中常简写为regex、regexp或RE，是计算机科学的一个概念。&lt;/p&gt;
&lt;p&gt;正则表通常被用来检索、替换那些符合某个模式(规则)的文本。&lt;/p&gt;
&lt;p&gt;正则表达式是对字符串（包括普通字符（例如，a 到 z 之间的字母）和特殊字符（称为“元字符”））操作的一种逻辑公式，就是用事先定义好的一些特定字符、及这些特定字符的组合，组成一个“规则字符串”，这个“规则字符串”用来表达对字符串的一种过滤逻辑。&lt;/p&gt;
&lt;p&gt;正则表达式是一种文本模式，模式描述在搜索文本时要匹配的一个或多个字符串。&lt;/p&gt;
&lt;p&gt;DFA 引擎在线性时状态下执行，因为它们不要求回溯（并因此它们永远不测试相同的字符两次）。&lt;br&gt;DFA 引擎还可以确保匹配最长的可能的字符串。&lt;br&gt;但是，因为 DFA 引擎只包含有限的状态，所以它不能匹配具有反向引用的模式；并且因为它不构造显示扩展，所以它不可以捕获子表达式。&lt;br&gt;
    
    </summary>
    
      <category term="安全" scheme="http://cookia.cc/categories/%E5%AE%89%E5%85%A8/"/>
    
    
      <category term="dos" scheme="http://cookia.cc/tags/dos/"/>
    
      <category term="正则表达式" scheme="http://cookia.cc/tags/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>华科印象</title>
    <link href="http://cookia.cc/2017/09/11/hust/"/>
    <id>http://cookia.cc/2017/09/11/hust/</id>
    <published>2017-09-11T14:16:40.000Z</published>
    <updated>2017-09-24T11:35:52.206Z</updated>
    
    <content type="html"><![CDATA[<p><img src="/assets/blogimg/notes/notes-1.jpg" width="50%"></p><p>人啊，总很珍惜回忆，也不是活在过去，<br>只是觉得人真正的财富，不是存在的那一串数字，<br>而是你正享受的现在和你脑海里存在的过去。<br>未来是期待，却不一定是你能拥有的。<br><a id="more"></a><br>来到新的环境已经两月有余，短短的两个月似乎过去了好久，<br>以至于刚刚结束的研究生生涯就已经在记忆中渐渐模糊了。<br>蓦然回首，惊觉记忆不如前啊。<br>也可能是累的。<br>虽说过去已是过去，但我还是喜欢以文字的形式记录下来。<br>于是，就有了华科印象。</p><p>细说印象之前，先来介绍一下华科。<br>官方名曰华中科技大学，老一辈称之为华工，我这一代人口中的华科，未来可能盛行的华中大，<br>以及很多人自嘲的关山口男子职业技术学院。<br>名字就像他的历史一样复杂。<br>然而他最神奇的不是这个，而是省内名气与武大比肩，出了省却只见武大，未闻华科。<br>记得一次与菊厂高管聊天<br>“哪里毕业的？”<br>“华科！”<br>“哦”<br>良久，追问一句<br>“在哪个城市？”<br>心里暗叹，保密工作做的这么好的，华科也算是在如今这浮躁社会的一股清流了。</p><h3 id="毛爷爷像和他背后的南一楼"><a href="#毛爷爷像和他背后的南一楼" class="headerlink" title="毛爷爷像和他背后的南一楼"></a>毛爷爷像和他背后的南一楼</h3><p><img src="/assets/blogimg/notes/notes-2.jpg" width="50%"></p><p>说到华科，就不得不说南大门的毛爷爷像。<br>这个如今被新生各种戏说解读的历史性雕塑，在早四十年那可是神圣不可侵犯的存在。<br>现在早已过了那个疯狂的年代，<br>没有亲身感受也就没法体会活在那个时代到底是一种怎样的经历。<br>只能从零零碎碎的文字间去窥见，去寻觅。</p><blockquote><p>“ 雕像大约是在1967年建起的。那时候学校还叫华中工学院，这尊雕像就是学校铸造厂打造的。雕像是钢筋水泥浇筑的，有人误以为是石膏的，其实外面用的是白水泥，所以是白色的。年代久了以后，因为风雨侵蚀，增出现了水渍印子，后来重新整修了一下，镶嵌了大理石。”<br><br></p><p>“ 印象里，华科是武汉最早建起毛主席雕像的地方，也是最高大的一尊。此后武汉的一些厂子和机关，也都建起了不少毛主席雕像。”<br><br></p><p>再后来，别的地方陆陆续续都拆了，唯有华科的一直留存至今。</p></blockquote><p>不管别人怎么去评论，我一直对这个雕像对历史持敬畏态度。<br>记得有次和实验室室友从外面回来，<br>路过雕像谈之，我表敬畏，他表不屑，<br>言毕，突然听他大骂一声，仰头捂鼻狂奔，原来是鼻血涓流不止，<br>我笑他，头上三尺有神明啊。<br>自此，再过雕像处，无不恭谨。</p><p>雕像背后靠着的是南一楼，算是华科老建筑里面标志性的建筑了，<br>也是承载了我两年来大部分记忆的地方了。<br>我是喜欢老建筑的，知道实验室在南一楼这老建筑里面，着实让我欢喜了一段时间。<br>走在里面，明显感觉到与近代建筑不同的沧桑和厚重感，<br>摸着剥落的墙壁前行，有种与历史交流的仪式感。<br>实验室在六楼，不大，也没有计算机系应有的科技感，<br>里面的杂乱和陈旧倒是和南一楼的沧桑相得益彰。</p><p>未完待续…</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;img src=&quot;/assets/blogimg/notes/notes-1.jpg&quot; width=&quot;50%&quot;&gt;&lt;/p&gt;
&lt;p&gt;人啊，总很珍惜回忆，也不是活在过去，&lt;br&gt;只是觉得人真正的财富，不是存在的那一串数字，&lt;br&gt;而是你正享受的现在和你脑海里存在的过去。&lt;br&gt;未来是期待，却不一定是你能拥有的。&lt;br&gt;
    
    </summary>
    
      <category term="随笔" scheme="http://cookia.cc/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
      <category term="印象" scheme="http://cookia.cc/tags/%E5%8D%B0%E8%B1%A1/"/>
    
  </entry>
  
</feed>
