<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>程默的博客 &#187; php</title>
	<atom:link href="http://blog.chacuo.net/tag/php/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.chacuo.net</link>
	<description>web原理、web架构、web安全、web性能、服务器性能、服务器架构、服务器安全;你不能预知明天，但你可以利用今天。你不能样样顺利，但你可以事事尽力!</description>
	<lastBuildDate>Mon, 31 Aug 2020 15:33:40 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>php header 重定向常出现功能(使用)漏洞</title>
		<link>http://blog.chacuo.net/276.html</link>
		<comments>http://blog.chacuo.net/276.html#comments</comments>
		<pubDate>Sat, 15 Jun 2013 09:45:28 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web安全]]></category>
		<category><![CDATA[header]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=276</guid>
		<description><![CDATA[php header函数功能强大，可以给用户发送各种header头信息，只要header头里面能够发送的内容， [...]]]></description>
				<content:encoded><![CDATA[<p>php header函数功能强大，可以给用户发送各种header头信息，只要header头里面能够发送的内容，都可以通过header函数来完成。如发送302跳转，设置cookie，发送401认证，发现last-modify等等！ HTTP/1.1 specification for more information on <acronym>HTTP</acronym> headers，都可以用该函数完成。总之一句话，任何服务区response应答的头信息几乎都可以用它来发送。如：</p>
<blockquote>
<pre><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image34.png"><img style="background-image: none; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="response 服务器响应头" alt="response 服务器响应头" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb34.png" width="572" height="222" border="0" /></a></pre>
</blockquote>
<pre></pre>
<pre>这里我们经常用header发送302跳转，会发现一个问题。在走查代码时候，遇到很多同人会有类似操作代码，如：</pre>
<blockquote>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Content-type: text/html; charset=utf-8&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">//判断用户是否授权</span></pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'用户未授权'</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;location:forbidden.php&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">///下面是进行摸个记录操作</span>
<span style="color: #666666; font-style: italic;">//删除条记录，或者修改某条记录……</span></pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="php" style="font-family:monospace;">&nbsp;</pre></td></tr></table></div>

</blockquote>
<p>这类代码，在开发中很常见，我们会发现，一个没有权限用户，操作该记录，网页会跳转到未授权页面，但是：<strong>记录任然被修改了</strong>，问题我们找到了，一般操作人员，对于js跳转会知道是前端浏览器跳转的。但是对于php操作跳转，<span style="color: #9b00d3;"><span style="text-decoration: underline;">错误认为是服务器跳转，好像php以执行到location，然后就终止了下面运行。 </span></span><span style="color: #000000;">其实，知道header函数真实意义就很容易理解了：<b>header()</b> is used to send a raw <acronym>HTTP </acronym>header！</span></p>
<p>header location 302实际上只是如下：</p>
<blockquote>
<pre><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image35.png"><img style="background-image: none; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="response 服务器302响应头" alt="response 服务器302响应头" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb35.png" width="576" height="266" border="0" /></a></pre>
<pre>跟其它普通echo 函数没有多大区别，只是给header信息头,echo 一行而已。</pre>
<pre></pre>
</blockquote>
<p><strong>屏蔽Bug方法：</strong></p>
<pre></pre>
<p>知道了，发送header跳转，服务器不会终止程序，因此为了安全起见。<span style="text-decoration: underline;"><span style="color: #9b00d3;">header locaction后，最好加一句exit()函数。</span></span> 这样，php解析引擎就会停止解析了！我们正确方法是封装个header_302方法</p>
<blockquote>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">/*header_302跳转*
 * *
 *@author http://blog.chacuo.net/
 * @param string $url 跳转url
 */</span>
<span style="color: #000000; font-weight: bold;">function</span>  header_302<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">headers_sent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
	<span style="color: #009900;">&#123;</span>
		<span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'header 已经发送过！'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;location:<span style="color: #006699; font-weight: bold;">$url</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

</blockquote>
<p>后记：这类问题，不光出在php程序中，其它很多header loction跳转语言程序，原理相同。都有类似功能，很多时候。都是使用时候没有注意，造成的。 容易在代码走查中，遗漏掉！好了，先到这里，欢迎交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/276.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>正则表达式（regex)入门、元字符(特殊字符)、学习提高、学习实例</title>
		<link>http://blog.chacuo.net/190.html</link>
		<comments>http://blog.chacuo.net/190.html#comments</comments>
		<pubDate>Mon, 10 Jun 2013 10:22:48 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web原理]]></category>
		<category><![CDATA[学习心得]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[正则表达式]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=190</guid>
		<description><![CDATA[什么是正则表达式呢？ 正则表达式，又称正规表示法、常规表示法（英语：Regular Expression，在代 [...]]]></description>
				<content:encoded><![CDATA[<ul>
<li>
<h3><font style="font-weight: bold">什么是正则表达式呢？</font></h3>
</li>
</ul>
<p>正则表达式，又称正规表示法、常规表示法（英语：Regular Expression，在代码中常简写为regex、regexp或RE），它是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。几乎在各种计算机编程语言中都有用到。可以分为普通正则表达式、扩展正则表达式、高级正则表达式。普通正则表达式在linux shell中常用到，高级正则表达式语法规范，基本由perl演化而来。目前常见程序语言（php,perl,python,java,c#)都支持高级正则表达式。</p>
<ul>
<li>
<h3><font style="font-weight: bold">我们为什么要学习正则表达式？</font></h3>
</li>
</ul>
<p>高级程序语言的正则表达式几乎都从perl语言发展而来，因此，语法几乎一致。你学好了，一门正则表达式语言。几乎在所有程序语言中就可以用到。就像，我知道sql语法，后端mysql,mssql几乎都通用。这个也是我们需要学好正则表达式一个原因，通用性。另外一个原因是：正则表达式强大的文本匹配功能。很多文本匹配处理，如果没有正则表达式，还真的很难做出来。如：从一段字符串，读出手机号格式，我们如果用字符串查找，需要做循环，需要写判断。估计耗费不少代码，开发时间。如果用正则表达式，就一行代码就可以了。匹配所有成对的：html标签，如果要做这个，我们发现非常复杂，要处理层次，要匹配标签。一般同人短短几个小时可能完成不了。如果用正则表达式，估计也就几分钟而已。</p>
<ul>
<li>
<h3><font style="font-weight: bold">正则表达式字符串格式</font></h3>
</li>
</ul>
<p>既然我们知道正则表达式重要性，通用性。那么我们对常见格式可以了解下。一般正则表达式由：普通字符+特殊字符（元字符）一起组成的字符串。如：匹配“ab开头，后面紧跟数字字符串“&#160;&#160; “ab\d+”&#160; 这其中ab就是普通字符，\d代表可以是0-9数字，+代表前面字符可以出现1次或以上。哈哈，看起来还真的很容易吧！</p>
<p>正则表达式无论是普通还是扩展还是高级正则表达式。不同之处，可能在特殊字符方面有些不同。很多特殊字符，可以组合，形成一套新匹配规则。这里就不说太深了。我们一般只要知道它的常见元字符。基本上常见正则表达式就可以写出来了。 </p>
<p>以下是javascript 正则表达式常见的<strong>元字符</strong>：</p>
<blockquote><div>
<table class="table" border="1" rules="all" cellspacing="0" frame="box">
<thead>
<tr valign="top">
<th width="16%">字符</th>
<th width="84%">描述</th>
</tr>
</thead>
<tbody>
<tr valign="top">
<td width="16%">\</td>
<td width="84%">将下一个字符标记为一个特殊字符、或一个原义字符、或一个 后向引用、或一个八进制转义符。例如，&#8217;n&#8217; 匹配字符 &quot;n&quot;。&#8217;\n&#8217; 匹配一个换行符。序列 &#8216;\\&#8217; 匹配 &quot;\&quot; 而 &quot;\(&quot; 则匹配 &quot;(&quot;。</td>
</tr>
<tr valign="top">
<td width="16%">^</td>
<td width="84%">匹配输入字符串的开始位置。如果设置了 <b>RegExp</b> 对象的 <b>Multiline</b> 属性，^ 也匹配 &#8216;\n&#8217; 或 &#8216;\r&#8217; 之后的位置。</td>
</tr>
<tr valign="top">
<td width="16%">$</td>
<td width="84%">匹配输入字符串的结束位置。如果设置了<b>RegExp</b> 对象的 <b>Multiline</b> 属性，$ 也匹配 &#8216;\n&#8217; 或 &#8216;\r&#8217; 之前的位置。</td>
</tr>
<tr valign="top">
<td width="16%">*</td>
<td width="84%">匹配前面的子表达式零次或多次。例如，zo* 能匹配 &quot;z&quot; 以及 &quot;zoo&quot;。 * 等价于{0,}。</td>
</tr>
<tr valign="top">
<td width="16%">+</td>
<td width="84%">匹配前面的子表达式一次或多次。例如，&#8217;zo+&#8217; 能匹配 &quot;zo&quot; 以及 &quot;zoo&quot;，但不能匹配 &quot;z&quot;。+ 等价于 {1,}。</td>
</tr>
<tr valign="top">
<td width="16%">?</td>
<td width="84%">匹配前面的子表达式零次或一次。例如，&quot;do(es)?&quot; 可以匹配 &quot;do&quot; 或 &quot;does&quot; 中的&quot;do&quot; 。? 等价于 {0,1}。</td>
</tr>
<tr valign="top">
<td width="16%">{<i>n</i>}</td>
<td width="84%"><i>n</i> 是一个非负整数。匹配确定的 <i>n</i> 次。例如，&#8217;o{2}&#8217; 不能匹配 &quot;Bob&quot; 中的 &#8216;o&#8217;，但是能匹配 &quot;food&quot; 中的两个 o。</td>
</tr>
<tr valign="top">
<td width="16%">{<i>n</i>,}</td>
<td width="84%"><i>n</i> 是一个非负整数。至少匹配<i>n</i> 次。例如，&#8217;o{2,}&#8217; 不能匹配 &quot;Bob&quot; 中的 &#8216;o&#8217;，但能匹配 &quot;foooood&quot; 中的所有 o。&#8217;o{1,}&#8217; 等价于 &#8216;o+&#8217;。&#8217;o{0,}&#8217; 则等价于 &#8216;o*&#8217;。</td>
</tr>
<tr valign="top">
<td width="16%">{<i>n</i>,<i>m</i>}</td>
<td width="84%"><i>m</i> 和 <i>n</i> 均为非负整数，其中<i>n</i> &lt;= <i>m</i>。最少匹配 <i>n</i> 次且最多匹配 <i>m</i> 次。刘， &quot;o{1,3}&quot; 将匹配 &quot;fooooood&quot; 中的前三个 o。&#8217;o{0,1}&#8217; 等价于 &#8216;o?&#8217;。请注意在逗号和两个数之间不能有空格。</td>
</tr>
<tr valign="top">
<td width="16%">?</td>
<td width="84%">当该字符紧跟在任何一个其他限制符 (*, +, ?, {<i>n</i>}, {<i>n</i>,}, {<i>n</i>,<i>m</i>}) 后面时，匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串，而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如，对于字符串 &quot;oooo&quot;，&#8217;o+?&#8217; 将匹配单个 &quot;o&quot;，而 &#8216;o+&#8217; 将匹配所有 &#8216;o&#8217;。</td>
</tr>
<tr valign="top">
<td width="16%">.</td>
<td width="84%">匹配除 &quot;\n&quot; 之外的任何单个字符。要匹配包括 &#8216;\n&#8217; 在内的任何字符，请使用象 &#8216;[.\n]&#8216; 的模式。</td>
</tr>
<tr valign="top">
<td width="16%">(<i>pattern</i>)</td>
<td width="84%">匹配<i>pattern</i> 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到，在VBScript 中使用 <b>SubMatches</b> 集合，在JScript 中则使用 <b>$0</b>…<b>$9</b> 属性。要匹配圆括号字符，请使用 &#8216;\(&#8216; 或 &#8216;\)&#8217;。</td>
</tr>
<tr valign="top">
<td width="16%">(?:<i>pattern</i>)</td>
<td width="84%">匹配 <i>pattern</i> 但不获取匹配结果，也就是说这是一个非获取匹配，不进行存储供以后使用。这在使用 &quot;或&quot; 字符 (|) 来组合一个模式的各个部分是很有用。例如， &#8216;industr(?:y|ies) 就是一个比 &#8216;industry|industries&#8217; 更简略的表达式。</td>
</tr>
<tr valign="top">
<td width="16%">(?=<i>pattern</i>)</td>
<td width="84%">正向预查，在任何匹配 <i>pattern</i> 的字符串开始处匹配查找字符串。这是一个非获取匹配，也就是说，该匹配不需要获取供以后使用。例如， &#8216;Windows (?=95|98|NT|2000)&#8217; 能匹配 &quot;Windows 2000&quot; 中的 &quot;Windows&quot; ，但不能匹配 &quot;Windows 3.1&quot; 中的 &quot;Windows&quot;。预查不消耗字符，也就是说，在一个匹配发生后，在最后一次匹配之后立即开始下一次匹配的搜索，而不是从包含预查的字符之后开始。</td>
</tr>
<tr valign="top">
<td width="16%">(?!<i>pattern</i>)</td>
<td width="84%">负向预查，在任何不匹配Negative lookahead matches the search string at any point where a string not matching <i>pattern</i> 的字符串开始处匹配查找字符串。这是一个非获取匹配，也就是说，该匹配不需要获取供以后使用。例如&#8217;Windows (?!95|98|NT|2000)&#8217; 能匹配 &quot;Windows 3.1&quot; 中的 &quot;Windows&quot;，但不能匹配 &quot;Windows 2000&quot; 中的 &quot;Windows&quot;。预查不消耗字符，也就是说，在一个匹配发生后，在最后一次匹配之后立即开始下一次匹配的搜索，而不是从包含预查的字符之后开始 </td>
</tr>
<tr valign="top">
<td width="16%"><i>x</i>|<i>y</i></td>
<td width="84%">匹配 <i>x</i> 或 <i>y</i>。例如，&#8217;z|food&#8217; 能匹配 &quot;z&quot; 或 &quot;food&quot;。&#8217;(z|f)ood&#8217; 则匹配 &quot;zood&quot; 或 &quot;food&quot;。 </td>
</tr>
<tr valign="top">
<td width="16%">[<i>xyz</i>]</td>
<td width="84%">字符集合。匹配所包含的任意一个字符。例如， &#8216;[abc]&#8216; 可以匹配 &quot;plain&quot; 中的 &#8216;a&#8217;。 </td>
</tr>
<tr valign="top">
<td width="16%">[^<i>xyz</i>]</td>
<td width="84%">负值字符集合。匹配未包含的任意字符。例如， &#8216;[^abc]&#8216; 可以匹配 &quot;plain&quot; 中的&#8217;p'。 </td>
</tr>
<tr valign="top">
<td width="16%">[<i>a-z</i>]</td>
<td width="84%">字符范围。匹配指定范围内的任意字符。例如，&#8217;[a-z]&#8216; 可以匹配 &#8216;a&#8217; 到 &#8216;z&#8217; 范围内的任意小写字母字符。 </td>
</tr>
<tr valign="top">
<td width="16%">[^<i>a-z</i>]</td>
<td width="84%">负值字符范围。匹配任何不在指定范围内的任意字符。例如，&#8217;[^a-z]&#8216; 可以匹配任何不在 &#8216;a&#8217; 到 &#8216;z&#8217; 范围内的任意字符。 </td>
</tr>
<tr valign="top">
<td width="16%">\b</td>
<td width="84%">匹配一个单词边界，也就是指单词和空格间的位置。例如， &#8216;er\b&#8217; 可以匹配&quot;never&quot; 中的 &#8216;er&#8217;，但不能匹配 &quot;verb&quot; 中的 &#8216;er&#8217;。 </td>
</tr>
<tr valign="top">
<td width="16%">\B</td>
<td width="84%">匹配非单词边界。&#8217;er\B&#8217; 能匹配 &quot;verb&quot; 中的 &#8216;er&#8217;，但不能匹配 &quot;never&quot; 中的 &#8216;er&#8217;。</td>
</tr>
<tr valign="top">
<td width="16%">\c<i>x</i></td>
<td width="84%">匹配由<i>x</i>指明的控制字符。例如， \cM 匹配一个 Control-M 或回车符。 <i>x</i> 的值必须为 A-Z 或 a-z 之一。否则，将 c 视为一个原义的 &#8216;c&#8217; 字符。 </td>
</tr>
<tr valign="top">
<td width="16%">\d</td>
<td width="84%">匹配一个数字字符。等价于 [0-9]。 </td>
</tr>
<tr valign="top">
<td width="16%">\D</td>
<td width="84%">匹配一个非数字字符。等价于 [^0-9]。 </td>
</tr>
<tr valign="top">
<td width="16%">\f</td>
<td width="84%">匹配一个换页符。等价于 \x0c 和 \cL。</td>
</tr>
<tr valign="top">
<td width="16%">\n</td>
<td width="84%">匹配一个换行符。等价于 \x0a 和 \cJ。</td>
</tr>
<tr valign="top">
<td width="16%">\r</td>
<td width="84%">匹配一个回车符。等价于 \x0d 和 \cM。</td>
</tr>
<tr valign="top">
<td width="16%">\s</td>
<td width="84%">匹配任何空白字符，包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。</td>
</tr>
<tr valign="top">
<td width="16%">\S</td>
<td width="84%">匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。</td>
</tr>
<tr valign="top">
<td width="16%">\t</td>
<td width="84%">匹配一个制表符。等价于 \x09 和 \cI。</td>
</tr>
<tr valign="top">
<td width="16%">\v</td>
<td width="84%">匹配一个垂直制表符。等价于 \x0b 和 \cK。</td>
</tr>
<tr valign="top">
<td width="16%">\w</td>
<td width="84%">匹配包括下划线的任何单词字符。等价于&#8217;[A-Za-z0-9_]&#8216;。 </td>
</tr>
<tr valign="top">
<td width="16%">\W</td>
<td width="84%">匹配任何非单词字符。等价于 &#8216;[^A-Za-z0-9_]&#8216;。 </td>
</tr>
<tr valign="top">
<td width="16%">\x<i>n</i></td>
<td width="84%">匹配 <i>n</i>，其中 <i>n</i> 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如， &#8216;\x41&#8242; 匹配 &quot;A&quot;。&#8217;\x041&#8242; 则等价于 &#8216;\x04&#8242; &amp; &quot;1&quot;。正则表达式中可以使用 ASCII 编码。.</td>
</tr>
<tr valign="top">
<td width="16%">\<i>num</i></td>
<td width="84%">匹配 <i>num</i>，其中 <i>num</i> 是一个正整数。对所获取的匹配的引用。例如，&#8217;(.)\1&#8242; 匹配两个连续的相同字符。 </td>
</tr>
<tr valign="top">
<td width="16%">\<i>n</i></td>
<td width="84%">标识一个八进制转义值或一个后向引用。如果 \<i>n</i> 之前至少 <i>n</i> 个获取的子表达式，则 <i>n</i> 为后向引用。否则，如果 <i>n</i> 为八进制数字 (0-7)，则 <i>n</i> 为一个八进制转义值。</td>
</tr>
<tr valign="top">
<td width="16%">\<i>nm</i></td>
<td width="84%">标识一个八进制转义值或一个后向引用。如果 \<i>nm</i> 之前至少有is preceded by at least <i>nm</i> 个获取得子表达式，则 <i>nm</i> 为后向引用。如果 \<i>nm</i> 之前至少有 <i>n</i> 个获取，则 <i>n</i> 为一个后跟文字 <i>m </i>的后向引用。如果前面的条件都不满足，若 <i>n</i> 和 <i>m</i> 均为八进制数字 (0-7)，则 \<i>nm</i> 将匹配八进制转义值 <i>nm</i>。</td>
</tr>
<tr valign="top">
<td width="16%">\<i>nml</i></td>
<td width="84%">如果 <i>n</i> 为八进制数字 (0-3)，且 <i>m</i> 和 <i>l</i> 均为八进制数字 (0-7)，则匹配八进制转义值 <i>nml。</i></td>
</tr>
<tr valign="top">
<td width="16%">\u<i>n</i></td>
<td width="84%">匹配 <i>n</i>，其中 <i>n</i> 是一个用四个十六进制数字表示的 Unicode 字符。例如， \u00A9 匹配版权符号 (?)。</td>
</tr>
</tbody>
</table></div>
</blockquote>
<p>&#160;</p>
<p>从上面元字符里面，我们看到，很多元字符，实际上可以代表一组普通字符。因此，我们要匹配一些字符串，正则表达式往往会有很多种。如：匹配0-9数字，可以用[0-9],\d,[0123456789] ，这样3种都可以，条条大路通罗马，都是对的。那么那一种正则表达式更好呢，性能更高呢，匹配速度更快呢？通过10万次 循环匹配，发现几种几乎相差不大，\d速度比[0-9快，[0-9]比[0123456789]快。从正则表达式精简]程度方面，\d最简单。使用时候，我们尽量用代表字符集元字符去匹配。精简且速度快！</p>
<ul>
<li>
<h3><font style="font-weight: bold">怎么样书写正则表达式呢？</font></h3>
</li>
</ul>
<h3><strong></strong></h3>
<p>我们写正则表达式，都是从分析匹配字符串特点开始，然后逐步补充其它元字符，普通字符。匹配从左到右。</p>
<p><strong>例如：我们要匹配一个手机号码。</strong></p>
<p>1. 分析字符串特点，手机号码是数字，并且是以1开头，11位长</p>
<p>2.可以写”1\d”&#160;&#160; 1开头，后面跟着数字 也可以是：1[0-9]</p>
<p>3.数字长度是11位 ，继续补充1\d{10} ，后面数字长11字符，也可以是：1[0-9]{10} ；{}里面数字，表示它左边字符可以重复出现次数</p>
<p>4.所有字符必须是11位，因此头尾直接必须满足条件，因此可以是：^1\d{10}$ 了。</p>
<p><strong>例如：我们匹配QQ号码</strong></p>
<p>1.分析QQ号码特点是，号码是 最少是5位数，首位字符非0，最大长度，目前到11位了</p>
<p>2.可以先定义首位字符，[1-9]\d&#160;&#160;&#160; 首位字符是1到9，后面是字符</p>
<p>3.后面字符个数在4到10位 [1-9]\d{4,10}</p>
<p>4.所有字符串必须都满足上面匹配，因为可以写成：^[1-9]\d{4,10}</p>
<p><strong>例如：匹配IP地址</strong></p>
<p>1.分析ip结构是，每节 0-255，中间用”.”分割，一共有4节</p>
<p>2.首先我们写第一个0-255 ，可以分解为0-9 一位数,10-99两位数,100-199三位数,200-249三位数第2节,250-255第四节</p>
<p>[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]&#160;&#160; “|”表示或者，计算优先级最低，左右两边可以是多个元字符普通字符组合字符串为一个整体。</p>
<p>3.这样的字符，有三次重复，中间加”.” ，所以结果是：</p>
<p>[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]\. ，因为是点字符是元字符，所有需要转义。这样是不是可以了呢，我们发现有问题，”|”优先级最低，这样会把最后\.字符表，组合为：“25[0-5] \.”了。因此，应该是前面几种情况，后面跟个”.”字符，正确是：([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\. ，这样就达到要求了。我们会发现，实际上每家一个()字符，都一个子匹配，会在匹配结果里面出现()内容。这里我们加()目的是，让优先计算，因此不需要里面子匹配内容。我们可以加忽略子匹配内容字符：?: ，结果将变为：(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\. </p>
<p>4.一段已经匹配到了，然后我们这样需要重复三次，我们可以直接重复上一个表达式3次：</p>
<p>方法一：(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.</p>
<p>方法二：把第一段作为分组，重复3次&#160;&#160;&#160; ((?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3} ，然后同样忽略子匹配结果，可以变为：</p>
<p>(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3} 哈哈，看到这个表达式是不是很晕了，其实一个长的表达式，都是从一点一点加上去的。这个利用到，重复次数，将结果简化不少了。</p>
<p>5.最后还有一段0-255匹配</p>
<p>(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) ，也就是在后面加多一个0-255匹配即可，然后在上面再加上头尾限定符，变成了：^(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$</p>
<p>下面一个图，是读一段文字里面，所有IP个格式地址</p>
<blockquote><p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image12.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb12.png" width="896" height="379" /></a></p>
<p>其中(?=……)是正向匹配，搜索左边字符串，并且该字符串右边必须满足?=后面匹配成功的才匹配成功！</p>
</blockquote>
<p>&#160;</p>
<p>好了，写了这么些例子，发现一口气能从很简单正则表达式，匹配到这么长的表达式了。是不是感觉有些晕了，其实不奇怪，长的正则表达式都是从简单正则表达式得到。逐步加上去了。 欢迎讨论交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/190.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>正则表达式（regex)或操作符&#8221;&#124;&#8220;使用易出现功能Bug</title>
		<link>http://blog.chacuo.net/187.html</link>
		<comments>http://blog.chacuo.net/187.html#comments</comments>
		<pubDate>Sun, 09 Jun 2013 11:05:27 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web原理]]></category>
		<category><![CDATA[学习心得]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[正则表达式]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=187</guid>
		<description><![CDATA[接上一篇：正则表达式（regex)错误使用导致功能漏洞 ，我们继续梳理，正则表达式错误使用，导致功能设计漏洞（ [...]]]></description>
				<content:encoded><![CDATA[<p>接上一篇：<a href="http://blog.chacuo.net/183.html">正则表达式（regex)错误使用导致功能漏洞</a> ，我们继续梳理，<strong>正则表达式</strong>错误使用，导致功能设计漏洞（bug），做web方面，需要掌握的知识很多，网站开发这项工作，在国内也就10多年，很多开发人员，都是通过：培训(自学) -&gt;模仿-&gt;做项目 ，这样一个过程。很多就是修修改改后，就成为了web开发工程师。这行入门低，很容易上手。但是想成为大师级的，还是很不容易。需要学习，掌握的知识几十门。而对于刚刚入门同人，很多时候因为缺乏系统学习，理论支持。导致提升有些心有余而力不足啦！因此，出现这些或多或少的功能设计漏洞，是很常见的！</p>
<p>好了，有些跑题了，在做代码走查时候，这类漏洞也是时常出现。我们看下，下面代码：</p>
<blockquote>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$user</span><span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;bcd123张三&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">///匹配用户名中出现abc还有bcd开头，后面紧跟是数字字符</span>
&nbsp;
<span style="color: #990000;">preg_match_all</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;/abc|bcd\d+/&quot;</span><span style="color: #339933;">,</span><span style="color: #000088;">$user</span><span style="color: #339933;">,</span><span style="color: #000088;">$match</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$match</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">/*结果是
array(1) {
  [0]=&gt;
  array(1) {
    [0]=&gt;
    string(6) &quot;bcd123&quot;
  }
}
*/</span></pre></td></tr></table></div>

<p>查找所有页面出现abc或者bcd开头，后面紧跟数字字符串。通过上面，我们看，正确匹配到bcd123，如果我们输入:$user = “abc123张三”， 发现不能匹配到了。原因是”|”字符，优先级最低，以上写法会变成：匹配abc 或者是bcd\d+ 字符串。</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image11.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb11.png" width="714" height="309" /></a> </p>
<p>以上图，将|，包含到()中。</p>
</blockquote>
<p>&#160;</p>
<p>如果要提升优先级，可以(abc|bcd)\d+ ，匹配所有abc或者bcd 字符串，并且后面紧跟数字的。在使用”|”字符串，注意它的优先级级别低，如果要优先匹配，可以放入（）中。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/187.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>姓名中点字符输入思考（输入特殊字符）</title>
		<link>http://blog.chacuo.net/174.html</link>
		<comments>http://blog.chacuo.net/174.html#comments</comments>
		<pubDate>Fri, 07 Jun 2013 14:46:53 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web原理]]></category>
		<category><![CDATA[学习心得]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[字符编码]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=174</guid>
		<description><![CDATA[最近工作中，时不时有用户输入自己真实姓名，然后申请银行提款时候，遇到一些特殊字符。而输入错误，提款失败！其中最 [...]]]></description>
				<content:encoded><![CDATA[<p>最近工作中，时不时有用户输入自己真实姓名，然后申请银行提款时候，遇到一些特殊字符。而输入错误，提款失败！其中最多就是少数名字，姓名中的点字符。如：某某·李四，经常有人输入：某某.李四 或 某某・李四。其中：”·・” 这2个中间点很容易输入错误。都是中间点，一个大一个细。</p>
<ul>
<li>
<h3><font style="font-weight: bold">那一个才是中文姓名中间点呢？</font></h3>
</li>
</ul>
<p>作为技术开发人员，我们有办法知道，到底那个点才是中文中间分割点。因为，这些都是常见姓名字符，因此，我们只要检测下，这2个字符对应在gb2312字符集中，字符编码即可。对于计算机而言，无论多怪的字符，看起来还怎么像，其实计算机本质去区分，是按照字符在字符集中，对应编码（字符编码）来保存、传输的。 因此，作为技术人员，只要能够判断字符在字符集中编码，就能知道对应字符是不是相同的。</p>
<blockquote><p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image9.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb9.png" width="785" height="203" /></a></p></blockquote>
<p>从上面看，在gb2312中，第一个字符编码是a1a4,第二个字符返回是%3F，这个是”?”，其实意思是，该字符在这个字符集gb2312中找不到，就默认返回”?”，经常做大字符集，转小字符集合时候常遇到。毫无疑问，我们可以确定第一个字符才是姓名中分隔符，第二个只是看起来更象中文分隔符字符而已。后来查询，发现，其实”・”是日文中的分隔符。通过这种方法，我们其实很容易通过程序就可以查出真假“李逵”啦！</p>
<ul>
<li>
<h3><font style="font-weight: bold">怎么样快速输入相似字符呢？</font></h3>
</li>
</ul>
<p>对于技术人员，已经知道怎么样辨别真假李逵了。 那么，如果有些自己常见的字符，我要去输入，我该怎么样去做呢？查询输入中文姓名中间点，方法很多。</p>
<blockquote><p><font style="background-color: #ffffff" face="Arial">1、智能ABC状态，直接按“`”键盘</font></p>
<p><font style="background-color: #ffffff" face="Arial">2、五笔输入法按，shiftv+ @键</font></p>
<p><font style="background-color: #ffffff" face="Arial">…… </font></p>
</blockquote>
<p><font style="background-color: #ffffff" face="Arial">这里省略N多方法，方法都能很快打印出字符，但是都有各自前提条件，都跟需要安装输入法有关系。如果，选择错误输入法，又很容易将相似字符输入进入。对于，普通用户，还是很难区分。</font></p>
<p><font style="background-color: #ffffff" color="#9b00d3" face="Arial"><u>我们必须找个，统一输入法，无论什么用户都可以正确输入！</u></font></p>
<p>我们知道目前最大字符集是unicode，也叫万国码，里面可以存储100多万字符，而且几乎所有字符集中，字符都在该字符集中能够找到，那么，我们只要知道字符在该字符中编码，就可以唯一确定一个字符。 对于windows而言，目前可以快速输入unicode码字符，只需要打开锁定数字键，按住：alt + unicode字符位置编码数字（小键盘）&#160; 即可。</p>
<p>如：我们发现”·” 字符unicode编码是 183，因此只要打开数字锁定键，按住alt + 小键盘输入183&#160;&#160; 松开alt即可。问题似乎变成了，怎么样知道字符的unicode编码了。</p>
<ul>
<li>
<h3><font style="font-weight: bold">怎么样知道字符unicode编码？</font></h3>
</li>
</ul>
<p>unicode由于字符非常多，因此，常有几种实现模式，utf-8,utf-16等。都是unicode字符集一种存储编码方式。我们只需要将任意字符转换到utf-32编码即可，utf-32每个字符用4个字节表示。结果，跟unicode值一致。只是都占用4个字节而已。</p>
<blockquote>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">///当前文件选择utf-8字符集</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
 *得到字符的unicode字符编码值*
 * @author QQ:8292669
 * @copyright http://blog.chacuo.net
 * @param string $char 传入单字符
 * @return int 10禁止字符值
 */</span>
<span style="color: #000000; font-weight: bold;">function</span> getUnicodeDec<span style="color: #009900;">&#40;</span><span style="color: #000088;">$char</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$c</span> <span style="color: #339933;">=</span> <span style="color: #990000;">iconv</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;utf-8&quot;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;utf-32BE&quot;</span><span style="color: #339933;">,</span><span style="color: #000088;">$char</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">///得到4个16进制字节</span>
	<span style="color: #b1b100;">return</span> <span style="color: #990000;">array_pop</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">unpack</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'N'</span><span style="color: #339933;">,</span><span style="color: #000088;">$c</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>   <span style="color: #666666; font-style: italic;">///16进制转换为10机制</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;·&quot;</span><span style="color: #339933;">,</span> getUnicodeDec<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'·'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">echo</span> <span style="color: #0000ff;">&quot;・&quot;</span><span style="color: #339933;">,</span> getUnicodeDec<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'・'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

</blockquote>
<blockquote><p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image10.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb10.png" width="547" height="228" /></a></p></blockquote>
<p>从上面，我们可以看到一个用alt+183,一个用alt+12539输入。 这样看起来输入很难记住，不过，如果某个人自己姓名刚好有特殊字符，这种方法是个不错选择。你只要记住自己姓名特殊字怎么输入就行。记住后，以后无论那个电脑上面，就可以准确无误输入。呵呵，是个不错的选择！如果，我姓名里面，有难打字符。要输入：程默，分别是：alt +31243,alt + 40664 就可以了。</p>
<p>后记：从技术角度分析下，其实我们遇到这类问题，都可以方便甄别，也可以有个一劳永逸的办法。当然，没有特殊难输入字符，完全没有必要去记录编码啦。 好了，就这里，欢迎朋友们交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/174.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>php session阻塞页面分析及优化 （session_write_close session_commit使用）</title>
		<link>http://blog.chacuo.net/168.html</link>
		<comments>http://blog.chacuo.net/168.html#comments</comments>
		<pubDate>Thu, 06 Jun 2013 11:17:59 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web原理]]></category>
		<category><![CDATA[web性能]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[session]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=168</guid>
		<description><![CDATA[这个问题很多做php开发朋友应该都有遇到过，一个启用了session_start 页面，由于执行时间过长。导致 [...]]]></description>
				<content:encoded><![CDATA[<p>这个问题很多做php开发朋友应该都有遇到过，一个启用了session_start 页面，由于执行时间过长。导致通一个用户访问，另外一个很简单的启用session_start页面一直阻塞着。 直到第一个页面执行完了。第二个页面就可以读取。这个就是，我们常说的，session阻塞机制。</p>
<ul>
<li>
<h3><strong>我用file 存放用户session</strong></h3>
</li>
</ul>
<p>session默认以文件保存，当一个用户访问session_start页面后，这个时候，就会默认创建一个包含session_id文件名，并且这个时候，会对文件进行锁定。如果这个用户点击链接，又访问一个该站session_start网页。这是，由于session_id一样，这个页面也有读取锁定该用户存放session文件。 由于，第一个页面没有执行完，它一直锁定了该文件。 第2个页面就不能获取锁，一直处于等待状态。</p>
<p>这样一个看似小的问题，实际上，如果网站上面有大量用户访问，会导致session读取文件一直阻塞等待着。用户浏览器一直跟服务器保持连接，会消耗很多服务器资源。web服务器活跃连接数也会增大，可能很快就会耗费完连接资源，出现拒绝服务器。</p>
<ul>
<li>
<h3><strong>我用memcache 存放用户session</strong></h3>
</li>
</ul>
<p>用memcache保存用户session，相比读取文件有很大速度提升。而且可以做到多服务器共享session。确实很方便，这个时候，我们发现不会出现用文件保存session锁定清理。memcached读取时候，是共享的，不会出现等待。但是，我们会发现，memcached连接数，还是会保持着。并且，连接数会增加，如果这个时候，你设置的memcached连接数过小，你会发现，很快memcached就挂死了。 这也是，做memcache接管session时候，经常遇到问题。 有时候，web服务器很多，session(memcache)很少。发现memcache莫名其妙死掉，可能跟这个有关系。太多反映很慢的页面(启动session)，会导致占用了大量memcached连接数。</p>
<ul>
<li>
<h3><strong>改变session使用习惯、优化调用方法</strong></h3>
</li>
</ul>
<p>其实，通过file或者session，如果处理耗时页面，都会带来服务器资源很大消耗。其实我们一般写入session或者读取时候，如果自己能够控制。用完了，就关闭掉文件锁，或者mem连接。就会自动释放资源，其实，php里面的：session_write_close，session_commit 函数就能做到改功能。我们看下下面代码执行过程：</p>
<blockquote><pre style="text-indent: 0px" lang="php">&lt;?php
ini_set('session.save_path','/tmp/');

function open($save_path, $session_name)
{
	echo __FUNCTION__,&quot;&lt;br /&gt;&quot;;
	return(true);
}
function close()
{
	echo __FUNCTION__,&quot;&lt;br /&gt;&quot;;
	return(true);
}
function read($id)
{
	echo __FUNCTION__,&quot;&lt;br /&gt;&quot;;
}
function write($id, $sess_data)
{
	echo __FUNCTION__,&quot;&lt;br /&gt;&quot;;
	return(true);
}
function destroy($id)
{
	echo __FUNCTION__,&quot;&lt;br /&gt;&quot;;
	return(true);
}
function gc($maxlifetime)
{
	echo __FUNCTION__,&quot;&lt;br /&gt;&quot;;
	return true;
}
session_set_save_handler(&quot;open&quot;, &quot;close&quot;, &quot;read&quot;, &quot;write&quot;, &quot;destroy&quot;, &quot;gc&quot;);
register_shutdown_function('test');

function test()
{
	echo __FUNCTION__,&quot;&lt;br /&gt;&quot;;
}
session_start();
echo 'aaaaa',&quot;&lt;br /&gt;&quot;;</pre>
</blockquote>
<p>&#160;</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image3.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb3.png" width="760" height="486" /></a> </p>
<p>启动”session_start” 会自动执行,open,read函数，然后页面执行完，会执行shutdown函数，最后会把session写入进去，然后执行close关闭文件。从session_start 到页面结束，会一直锁定文件或者保持连接的。</p>
<p>我们如果 执行完session_start后，执行”session_commit();” 看看结果</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image4.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb4.png" width="495" height="202" /></a><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image5.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb5.png" width="395" height="271" /></a>&#160; </p>
<p><strong>执行过程：</strong>执行commit后，直接会调用，wirte,close操作。直接关闭文件或者关闭连接(memcache)了。 </p>
<p><strong></strong></p>
<ul>
<li>
<h3><strong>我们的问题</strong></h3>
</li>
</ul>
<h3>1.我们页面有多次写入，怎么样操作？</h3>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image6.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb6.png" width="472" height="228" /></a> <a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image7.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb7.png" width="414" height="170" /></a> </p>
<p>&#160;</p>
</p>
</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image8.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb8.png" width="474" height="310" /></a> </p>
<p>第一次写入后，然后提交，再次打开写入，然后再次提交。我们发现，2次数据都保存到用户session中了。</p>
<p>&#160;</p>
<ul>
<li>
<h3><strong>我们来总结下吧</strong></h3>
</li>
</ul>
<p>1.只读取session页面，建议打开后，就直接commit，这是$_SESSION变量已经生成了。</p>
<p>2.有对session进行写入页面，建议修改完$_SESSION后，直接调用commit</p>
<p>3.多次打开并且写入，这个不建议使用，比较打开文件，写入都是耗费时间的。如果能一次搞定的，就不要做多次了。 除非，中间执行很耗时的业务。 </p>
<p>后记：其实，使用完session，随手commit也不是坏事，养成习惯后。可以节省性能，减少服务器开销。是个不错选择！欢迎大家交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/168.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web文件操作常见安全漏洞（目录、文件名检测漏洞）</title>
		<link>http://blog.chacuo.net/152.html</link>
		<comments>http://blog.chacuo.net/152.html#comments</comments>
		<pubDate>Wed, 05 Jun 2013 10:35:54 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web安全]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[文件操作漏洞]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=152</guid>
		<description><![CDATA[做web开发，我们经常会做代码走查，很多时候，我们都会抽查一些核心功能，或者常会出现漏洞的逻辑。随着技术团队的 [...]]]></description>
				<content:encoded><![CDATA[<p>做web开发，我们经常会做代码走查，很多时候，我们都会抽查一些核心功能，或者常会出现漏洞的逻辑。随着技术团队的壮大，组员技术日益成熟。 常见傻瓜型SQL注入漏洞、以及XSS漏洞。会越来越少，但是我们也会发现一些新兴的隐蔽性漏洞偶尔会出现。这些漏洞，跟多来自开发人员，对一个函数、常见模块功能设计不足，遗留下的问题。以前我们能够完成一些功能模块，现在要求是要安全正确方法完成模块才行。 接下来，我会分享一些常见功能模块，由于设计原因导致漏洞出现。下面，我们先看下，读取文件型功能漏洞。</p>
<p>我们先看下下面一段代码，通过用户输入不同目录，包含不同文件</p>
<blockquote><pre style="text-indent: 0px" lang="php">&lt;?php
///读取模块名称
$mod = isset($_GET['m'])?trim($_GET['m']):'index';

///过滤目录名称不让跳转到上级目录
<strong><u>$mod = str_replace("..",".",$mod);</u></strong>

///得到文件
<strong><u>$file = "/home/www/blog/".$mod.".php";</u></strong>

///包含文件
@include($file);

</pre>
<pre></pre>
</blockquote>
<p>这段代码，可能在很多朋友做的程序里面有遇到过，对于新人来说，也是很容易出现这样问题，记得走查遇到该代码时候，我问到，你这个代码安全方面能做到那些？</p>
<p>答：1. 对”..”目录有做替换，因此用户传入模块名里面有有..目录都会被替换掉了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.构造拼接file名称，有前面目录限制，有后面扩展名限制，包含文件就会限制在该目录了</p>
<ul>
<li>
<h3><strong>这段代码真的做到了目录安全检测吗？</strong></h3>
</li>
</ul>
<p>我们来测试下，如果$mod传入这个值将会是什么样的结果。</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image1.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb1.png" width="587" height="96"></a> </p>
<p>$mod 通过构造输?mod=&#8230;%2F&#8230;%2F&#8230;%2F&#8230;%2Fetc%2Fpasswd%00 ，我们看结果将是：</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/06/image2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/06/image_thumb2.png" width="593" height="304"></a> </p>
<p>居然include(“/etc/passwd”)文件了。 </p>
<ul>
<li>
<h3><strong>怎么逃脱了我参数限制呢？</strong></h3>
</li>
</ul>
<h3><strong></strong>&nbsp;</h3>
<p><strong>首先：</strong>做参数过滤类型去限制用户输入本来就不是一个好方法，一般规则是：<u><font color="#0000ff">能够做检测的，不要做替换 </font></u>只要是检测不通过的，直接pass 掉！这是我们的一个原则。过滤失败情况，举不胜举，我们来看看，实际过程。</p>
<p>1、输入”…/…/…/” 通过把”..” 替换为”.”后</p>
<p>2、结果是”../../../” 就变成了这个了</p>
<p>有朋友就会说，如果我直接替换为空格是不是就好了？在这个里面确实可以替换掉。但是不代表以后你都替换为空格就好了。再举例子下。如：有人将字符串里面javascript替换掉。代码如下：</p>
<blockquote>
<p>……</p>
<p><font style="background-color: #ffffff" face="Arial">$msg = str_replace(“javascript”,””,$msg);</font></p>
</blockquote>
<p><u>看似不会出现了javascript了，但是，如果输入:jjavascriptavascript 替换，会替换掉中间一个变为空格后。前面的”j” 跟后面的会组成一个新的javascript了。 </u></p>
<p><strong>其次：</strong>我们看看，怎么逃脱了，后面的.php 限制呢。用户输入的参数有：”etc/passwd/0” ，\0字符非常特殊，一段连接后，文件名称变成了”……etc/passwd\0.php”，你打印出该变量时候，还是正确的。但是，一段放入到文件读写操作方法里面，\0后面会自动截断。操作系统，只会读取……etc/passwd文件了。 “\0”会出现在所有文件系统读写文件变量中。都会同样处理。这根c语言\0作为字符串完整标记有关系。</p>
<p>通过上面分析，大家发现做文件类型操作时候，一不注意将产生大的漏洞。而且该漏洞就可能引发一系列安全问题。</p>
<ul>
<li>
<h3><strong>该怎么做文件类操作呢？</strong></h3>
</li>
</ul>
<p>到这里，估计有人就会思考这个，做文件读写操作时候，如果路径里面有变量时候，我该怎么样做呢？有人会说，替换可以吗？ “可以”，但是这个方法替换不严格，将会出现很多问题。而且，对于初写朋友，也很难杜绝。做正确的事情，选择了正确的方法，会从本身杜绝问题出现可能了。 这里，我建议：对于变量做白名单限制。</p>
<ol>
<li><strong>什么是白名单限制</strong><br />
<blockquote>
<p><font style="background-color: #ffffff" face="Arial">举例来说：</font></p>
<p>$mod = isset($_GET['m'])?trim($_GET['m']):&#8217;index&#8217;;<font style="background-color: #ffffff" face="Arial"> ///读取模块名称后</font></p>
<p><font style="background-color: #ffffff" face="Arial">mod变量值范围如果是枚举类型那么：</font></p>
<p><font style="background-color: #ffffff" face="Arial">if(!in_array($mod,array(‘user’,’index’,’add’,’edit’))) exit(‘err!!!’);</font></p>
<p><font style="background-color: #ffffff" face="Arial">完全限定了$mod，只能在这个数组中，<strong>够狠！！！！</strong></font></p>
<p>&nbsp;</p>
</blockquote>
<li><strong>怎么做白名单限制</strong></li>
</ol>
<p>通过刚才例子，我们知道如果是枚举类型，直接将值放到list中即可，但是，有些时候，这样不够方面。我们还有另外一个白名单限制方法。就是<strong>限制字符范围</strong></p>
<blockquote>
<p><font style="background-color: #ffffff" face="Arial">举例来说：</font></p>
<p>$mod = isset($_GET['m'])?trim($_GET['m']):&#8217;index&#8217;;<font style="background-color: #ffffff" face="Arial"> ///读取模块名称后</font></p>
<p>我限制知道$mod是个目录名称，对于一般站点来说，就是字母加数字下划线之类。</p>
<p>if(!preg_match(“/^\w+$/”,$mod)) exit(‘err!!!’);</p>
<p>字符只能是：[A-Za-z0-9_] 这些了。<strong>够狠！！！</strong></p>
</blockquote>
<p>&nbsp;</p>
<p><strong>总结：</strong>是不是发现，白名单限制方法，做起来其实很简单，你知道那个地方要什么，就对输入检测必须是那些。而且，检测自己已知的，比替换那些未知的字符，是不是简单多了。 好了，先到这里，正确的解决问题方法，会让文件简单，而且更安全！！欢迎交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/152.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>识别真假搜索引擎（搜索蜘蛛）方法（baidu,google,Msn,sogou,soso等)</title>
		<link>http://blog.chacuo.net/147.html</link>
		<comments>http://blog.chacuo.net/147.html#comments</comments>
		<pubDate>Tue, 04 Jun 2013 11:10:16 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web原理]]></category>
		<category><![CDATA[学习心得]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[搜索引擎]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=147</guid>
		<description><![CDATA[最近工作中遇到个问题，就是有一些资源，不希望别人很派发的抓取，这样会占用我们带宽还有资源。因此，我们对页面访问 [...]]]></description>
				<content:encoded><![CDATA[<p>最近工作中遇到个问题，就是有一些资源，不希望别人很派发的抓取，这样会占用我们带宽还有资源。因此，我们对页面访问做了频率限制。这样一来，又怕搜索蜘蛛给限制了。 因此，我们有个需求，就是除了常见搜索蜘蛛，其它都要做频率限制。 工作就变成了，首先我们怎么样正确表示搜索蜘蛛。</p>
<ul>
<li>
<h3><strong>怎么样识别搜索蜘蛛</strong></h3>
</li>
</ul>
<h3><strong></strong></h3>
<p>搜索引擎基本上由最先google,和国内的baidu统一了。刚开始比较混乱，后期有很多规则协议，可以遵循。基本上一些新兴的搜索引擎在访问站点时候，都会延用google制定的一些规则。它们一般都会有特定的user-agent，但是，如果我们只通过user-agent去识别搜索蜘蛛的话，那样第三方抓取程序，都会去伪造个user-agent。变成搜索蜘蛛的，如：Googlebot/2.1 (+<a href="http://www.googlebot.com/bot.html)%C2%A0">http://www.googlebot.com/bot.html) </a>是，google蜘蛛的值。</p>
<p>现在一般搜索引擎都提供一个DNS 反向IP查询功能，只需要把访问来的IP 通过反向查询域名，看是不是搜索引擎域名。这样伪造的爬虫工具，就会被很容易识别了。 具体识别真假蜘蛛只需要：<u><font color="#0000ff">1，判断user-agent是否满足蜘蛛格式 2，然后进一步确定IP 反解析域名是否属于该搜索引擎域名.</font></u></p>
<table class="table" border="0" cellspacing="1" cellpadding="4" width="732" align="center">
<tbody></tbody>
<thead>
<tr>
<td width="102"><strong>搜索引擎</strong></td>
<td width="104"><strong>user-agent(包含)</strong></td>
<td width="77"><strong>是否PTR</strong></td>
<td width="442"><strong>备注</strong></td>
</tr>
</thead>
<tbody>
<tr>
<td width="102">google</td>
<td width="104">Googlebot</td>
<td width="77">√</td>
<td width="442">host ip&#160; 得到域名：googlebot.com主域名</td>
</tr>
<tr>
<td width="102">baidu</td>
<td width="104">Baiduspider</td>
<td width="77">√</td>
<td width="442">host ip&#160; 得到域名：*.baidu.com 或 *.baidu.jp</td>
</tr>
<tr>
<td width="102">yahoo</td>
<td width="104">Yahoo!</td>
<td width="77">√</td>
<td width="442">host ip&#160; 得到域名：inktomisearch.com主域名 </td>
</tr>
<tr>
<td width="102">Sogou</td>
<td width="104">Sogou</td>
<td width="77">×</td>
<td width="442">
<p>*Sogou web spider/3.0(+<a href="http://www.sogou.com/docs/help/webmasters.htm#07&Prime;)&nbsp;">http://www.sogou.com/docs/help/webmasters.htm#07″) </a>            <br />*Sogou Push Spider/3.0(+<a href="http://www.sogou.com/docs/help/webmasters.htm#07&Prime;)&nbsp;">http://www.sogou.com/docs/help/webmasters.htm#07″) </a></p>
</td>
</tr>
<tr>
<td width="102">网易</td>
<td width="104">YodaoBot</td>
<td width="77">×</td>
<td width="442">*Mozilla/5.0 (compatible; YodaoBot/1.0; <a href="http://www.yodao.com/help/webmaster/spider/%E2%80%9D;">http://www.yodao.com/help/webmaster/spider/”;</a> ) </td>
</tr>
<tr>
<td width="102">MSN</td>
<td width="104">MSNBot</td>
<td width="77">√</td>
<td width="442">host ip&#160; 得到域名：live.com主域名</td>
</tr>
<tr>
<td width="102">360</td>
<td width="104">360Spider</td>
<td width="77">×</td>
<td width="442">Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.0.11)&#160; Firefox/1.5.0.11; 360Spider</td>
</tr>
<tr>
<td width="102">soso</td>
<td width="104">Sosospider</td>
<td width="77">×</td>
<td width="442">Sosospider+(+http://help.soso.com/webspider.htm)</td>
</tr>
<tr>
<td width="102">bing</td>
<td width="104">bingbot</td>
<td width="77">√</td>
<td width="442">host ip&#160; 得到域名：msn.com主域名</td>
</tr>
</tbody>
</tbody>
</table>
<p>以上是我整理一些常用搜索引擎的user-agent特征码，以及IP反向解析情况。保证准确识别搜索引擎，我们通过IP反解析是最为准确方法。好在google,baidu,bing都有做反向解析。基本上占用了80%搜索市场了。下面，我是我检测方法。</p>
<ul>
<li>
<h3><strong>PHP反解析IP方法</strong></h3>
</li>
</ul>
<blockquote><pre style="text-indent: 0px" lang="php">&lt;?php
/**
 *检查IP及蜘蛛真实性
 * (check_spider('66.249.74.44',$_SERVER['HTTP_USER_AGENT']));
 * @copyright  http://blog.chacuo.net
 * @author 8292669
 * @param string $ip IP地址
 * @param string $ua ua地址
 * @return false|spidername  false检测失败不在指定列表中
 */
function check_spider($ip,$ua)
{
	static $spider_list=array(
	'google'=&gt;array('Googlebot','googlebot.com'),
	'baidu'=&gt;array('Baiduspider','.baidu.'),
	'yahoo'=&gt;array('Yahoo!','inktomisearch.com'),
	'msn'=&gt;array('MSNBot','live.com'),
	'bing'=&gt;array('bingbot','msn.com')
	);
	
	if(!preg_match('/^(\d{1,3}\.){3}\d{1,3}$/',$ip)) return false;
	if(empty($ua)) return false;
 
	foreach ($spider_list as $k=&gt;$v)
	{
		///如果找到了
		if(stripos($ua,$v[0])!==false)
		{
			$domain = gethostbyaddr($ip);

			if($domain &amp;&amp; stripos($domain,$v[1])!==false)
			{
				return $k;
			}
		}
	}
	return false;
}</pre>
</blockquote>
<p>&#160;</p>
<p>目前只加入几个搜索引擎检测，这些是可以做反解析查询的。不能做反解析查询的，最好做速度限制，用户会使用它们来伪造搜索引擎来抓取你的资源。欢迎大家交流，先写到这里了。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/147.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web上存漏洞及原理分析、防范方法（安全文件上存方法）</title>
		<link>http://blog.chacuo.net/142.html</link>
		<comments>http://blog.chacuo.net/142.html#comments</comments>
		<pubDate>Mon, 03 Jun 2013 10:08:42 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web安全]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[上存漏洞]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=142</guid>
		<description><![CDATA[看我上两篇，我们知道，上存漏洞常见有，文件名检测漏洞，还有就是文件格式检查漏洞。 另外还有个一个，就是保存文件 [...]]]></description>
				<content:encoded><![CDATA[<p>看我上两篇，我们知道，上存漏洞常见有，<a href="http://blog.chacuo.net/136.html" target="_blank">文件名检测漏洞</a>，还有就是<a href="http://blog.chacuo.net/141.html" target="_blank">文件格式检查漏洞</a>。 另外还有个一个，就是保存文件存在漏洞。这类漏洞，主要是可以读取用户传入路径名称，采用不正确的过滤方法，导致恶意用户，将文件上存到非预期的地方，带来安全隐患。</p>
<p>其实，我们抓住几个地方即可，我们先来分析下，既然用户要上存文件，而且文件将是多种多样格式；可能有的文件内容与用户传入格式不一致，有的文件内容还夹杂木马代码。 那么，我们让用户上存文件，跟站点文件做一个分别授权，做隔离。</p>
<ul>
<li>
<h3><strong><span style="text-decoration: underline;">让保存上存目录独立开来，目录权限只读不能执行</span></strong></h3>
</li>
</ul>
<p>这一步从系统设计加以授权，无论你上次什么文件，都不可能执行到。就算我不做任何检测，你的文件都上存到这里了，也不会对我系统构成安全。（如果有用户上存一些反动言语的图片，那另外需要处理的）</p>
<h3></h3>
<ul>
<li>
<h3><strong><span style="text-decoration: underline;">不直接使用服务器传入值，所有都要进行检测</span></strong></h3>
</li>
</ul>
<p>这类跟我们做一切输入都是有害原则一样，对于客户端传入的：type, name ，都要进行判断，不直接使用。对于要生成到某个目录，某个文件名。</p>
<p><span style="text-decoration: underline;"><strong>文件名</strong>最好方法是：自己写死目录（不要读取传入目录），文件名，最好自己随机生成，不读取用户文件名。文件扩展名，可以取最右边”.”后面字符。</span></p>
<p>以上2个方法，刚好从2个方面对上存做了整体约束。</p>
<p>方法2 ： 保存上存文件名，按照自己指定目录写入，并且文件名自己生成的。</p>
<p>方法1：只要保证文件写对了位置，然后从配置上，对写入目录进行权限控制，这个是治本。可以做到，你无论上存什么文件，都让你没有权限跳出去可以运行。</p>
<p>&nbsp;</p>
<p>以上2个方法，一起使用，可以保证文件正确存到地方，然后，权限可以控制。 这里顺便说明下， 判断用户上存文件是否满足要求类型，就直接检查文件扩展名，只要满足扩展名就让上存。 反正，做了执行权限限制，你不按要求上存内容，也无妨。 反正，不能执行，也不会有多大危害性的。</p>
<ul>
<li><strong>正确步骤：</strong></li>
</ul>
<p><span style="text-decoration: underline;"><span style="color: #0000ff;">1.读取文件名，验证扩展名是不是在范围内</span></span></p>
<p><span style="text-decoration: underline;"><span style="color: #0000ff;">2.自己定义生成的文件名，目录，扩展名可以来自文件名扩展名。 其它值，都自己配置，不读取上存中内容</span></span></p>
<p><span style="text-decoration: underline;"><span style="color: #0000ff;">3.将文件 移到新目录(这个目录权限设置只读)</span></span></p>
<p>&nbsp;</p>
<p>好了，以上是一般操作方法，希望对大家有帮助，也欢迎朋友们交流！也希望提供更好的方法！接下来，我会在web 开发中，常见一些方法功能安全设计方面继续写一些我的心得，看法！ 欢迎大家随时交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/142.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web上存漏洞及原理分析、防范方法（文件类型检测漏洞）</title>
		<link>http://blog.chacuo.net/141.html</link>
		<comments>http://blog.chacuo.net/141.html#comments</comments>
		<pubDate>Sun, 02 Jun 2013 08:59:00 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web安全]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[上存漏洞]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=141</guid>
		<description><![CDATA[通过上一篇文章，我们知道wed上存漏洞，最常见一种是文件名检测漏洞，接下来，我们看看另外一种漏洞，上存文件类型 [...]]]></description>
				<content:encoded><![CDATA[<p>通过上一篇文章，我们知道wed上存漏洞，<a href="http://blog.chacuo.net/136.html" target="_blank">最常见一种是文件名检测漏洞</a>，接下来，我们看看另外一种漏洞，上存文件类型漏洞，这也是一种较为容易出现问题。</p>
<p>我当时就想，既然我知道我需要允许上存什么样的文件，那么，我就只允许你上存该文件。只要我文件类型判断准确了，你想上存能够执行的代码。我都给阻止掉，不就行了吗？ 这确实，是个好的方法，但是我们再做的时候，往往会出现下面一些问题。</p>
<p>这里我们看下常见实现的php代码。 这里，常见两个问题是：</p>
<blockquote><p><font style="background-color: #ffffff" face="Arial"></font></p>
<p><font style="background-color: #ffffff" face="Arial"><strong><u>1.读取文件type,直接做文件类型判断</u></strong></font></p>
<p><font style="background-color: #ffffff" face="Arial"><u><strong>2.通过工具分析文件格式，以此来确认文件类型</strong></u></font></p>
<p><font style="background-color: #ffffff" face="Arial"></font></p>
</blockquote>
<ul>
<li>
<h3><strong>问题一：读取文件type，判断文件类型</strong></h3>
</li>
</ul>
<blockquote><pre>&#160;</pre>
<pre style="text-indent: 0px">if(isset($_FILES['img']))
{
    $file = save_file($_FILES['img']);
	if($file===false) exit('上存失败！');
	
	echo &quot;上存成功！&quot;,$file;
}



function check_file($img)
{
	///读取文件
	if($img['error']&gt;0) return false;
	
	$type = $img['type'];
	$filename = $img['name'];
	
	
	///读取文件扩展名
	$len=strrpos($filename,&quot;.&quot;);
	if($len===false) return false;
	
	//得到扩展名
	$ext = strtolower(substr($filename,$len+1));
	
	///判断文件类型
	<strong><u><font color="#0000ff">if($type &amp;&amp; preg_match('%^image/.+$%',$type)) return $ext;</font></u></strong>
	
	return false;
}

function save_file($img)
{
	$ext = check_file($img);
	if(!ext) return false;
	
	//格式检测ok，准备移动数据
	<strong><u><font color="#0000ff">$filename = time().$ext;</font></u></strong>
	$newfile = &quot;upload/&quot; .$filename;
	if(!move_uploaded_file($img[&quot;tmp_name&quot;],$newfile)) return false;
	
	return $newfile;

}</pre>
</blockquote>
<h3><strong></strong></h3>
<p>以上加蓝色代码，是关键，这个里面我们直接读取type类型，也就是文件内容。通过第一篇知识：<a href="http://blog.chacuo.net/108.html" target="_blank">web上存漏洞及原理分析、防范方法</a> 我们知道，type来自浏览器端浏览器自动传入变量。 如果是浏览器，这个值一般没有问题。但是，如果是来自用户自己组织的包，他可以给type 设置个：image/jpeg值， 然后，给name 一个 index.php 值。 </p>
<p><u><font color="#ff0000">估计大家已经看到问题，这样一来，我们生成的文件$filename变成为：time().’php’了。 就创建一个php文件。</font></u></p>
<ul>
<li>
<h3><strong>通过工具分析文件格式，以此来确认文件类型</strong></h3>
</li>
</ul>
<h1><strong></strong></h1>
<p>我们已经清楚知道了,type值是可以随便构造的，这类检查用户类型方法。是没有任何作用，恶意用户，可以随便给一个php文件发送上来，传一个image类型。 那么，肯定有朋友会说，我直接用php程序，去分析用户传入的tmp_name 文件格式，这个总靠谱吧！ 我们看看下面代码。</p>
<blockquote>
<pre style="text-indent: 0px">function check_file($img)
{
	///读取文件
	if($img['error']&gt;0) return false;
	
	$typelist = array(array(&quot;FFD8FFE1&quot;,&quot;jpg&quot;),
	array(&quot;89504E47&quot;,&quot;png&quot;),
	array(&quot;47494638&quot;,&quot;gif&quot;),
	array(&quot;49492A00&quot;,&quot;tif&quot;),
	array(&quot;424D&quot;,&quot;bmp&quot;));
	
	$file = $img['tmp_name'];
	$filename = $img['name'];
	
	
	///读取文件扩展名
	$len=strrpos($filename,&quot;.&quot;);
	if($len===false) return false;
	
	//得到扩展名
	$ext = strtolower(substr($filename,$len+1));
	
	///判断文件类型
	//读取文件开头15字节，一般通过这些字节值，可以确定它的格式
	$file = @fopen($file,&quot;rb&quot;);
	$bin = fread($file, 15);
	
	foreach ($typelist as $v)
	{
		$blen=strlen(pack(&quot;H*&quot;,$v[0])); //得到文件头标记字节数
		$tbin=substr($bin,0,intval($blen)); ///需要比较文件头长度
		 
		<strong><u><font color="#0000ff">if(strtolower($v[0])==strtolower(array_shift(unpack(&quot;H*&quot;,$tbin))))</font></u></strong> 
		{
			return $ext;
		}
	}
	
	return false;
}</pre>
</blockquote>
<p>该方法，直接分析用户传入文件格式，然后决定该文件类型，是否允许保存！这套，我们看来非常可靠方法，应该很准确，应该没有问题，不读取type,自己来分析格式。 其实：如果用户传入一个文件，前面4字节是：89504E47， 然后，后面加入一段&lt;?php代码 。上存的文件名称是image.php 。这样一来，我们发现，这段代码保存为php文件了。 只是这个文件，前面一部分可能是图片格式，后面一部分，只纯粹的php 程序。 通过浏览器，去访问下这个，还真的可以运行呢。 很久以前，就有人做过image图片木马。可以去百度搜索：”<u>将php木马隐藏在图片里</u>” ，这样做出的文件，你用画图软件看是个图片，你如果用php运行这段代码，里面php能够执行了。 </p>
<p>&#160;</p>
<p>好了，我们总结下，看来通过type判断类型，以及通过文件格式检测类型。 都不能很好解决，准确判断用户上存文件格式了。 其实，我们反过来想想，文件格式，不是通过一个简单字节标识码就能够准确判断的。 如果真的要去检测文件类型，我们该用什么方法呢？如果真的要检测格式，例如是图片，可以用php gd库，直接去打开文件，然后再保存一次。 这样，里面不合法的代码会去掉的。但是，我们想想，这样该会花费多大的性能呢？</p>
<p>综上所述，其实，去判断文件内容格式，不是明智的方法。 会非常复杂，而且也容易出现问题。想准确判断，还会消耗大量的服务器资源。除非万不得已，我们不要去尝试做这种操作。 接下来，对于安全上存方法，我会说说思路，欢迎交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/141.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web上存漏洞及原理分析、防范方法（文件名检测漏洞）</title>
		<link>http://blog.chacuo.net/136.html</link>
		<comments>http://blog.chacuo.net/136.html#comments</comments>
		<pubDate>Sat, 01 Jun 2013 15:09:59 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web安全]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[上存漏洞]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=136</guid>
		<description><![CDATA[我们通过前篇：web上存漏洞及原理分析、防范方法 学习，已经知道后端获取服务器变量，很多来自客户端传入的。跟普 [...]]]></description>
				<content:encoded><![CDATA[<p>我们通过前篇：<a href="http://blog.chacuo.net/108.html">web上存漏洞及原理分析、防范方法</a> 学习，已经知道后端获取服务器变量，很多来自客户端传入的。跟普通的get,post没有什么不同。下面我们看看，常见出现漏洞代码。</p>
<h3><font style="font-weight: bold">1、检测文件类型，并且用用户上存文件名保存</font></h3>
<blockquote><pre style="text-indent: 0px">if(isset($_FILES['img']))
{
    $file = save_file($_FILES['img']);
	if($file===false) exit('上存失败！');
	
	echo &quot;上存成功！&quot;,$file;
}

function check_file($img)
{
	///读取文件
	if($img['error']&gt;0) return false;
	
	$tmpfile = $img['tmp_name'];
	$filename = $img['name'];
	
	
	///读取文件扩展名
	$len=strrpos($filename,&quot;.&quot;);
	if($len===false) return false;
	
	//得到扩展名
	$ext = strtolower(substr($filename,$len+1));
	if(!in_array($ext,array('jpg','jpeg','png'))) return false;
	return true;
}

function save_file($img)
{
	if(!check_file($img)) return false;
	
	//格式检测ok，准备移动数据
	<strong>$filename = $img['name'];</strong>
	$newfile = &quot;upload/&quot; .$filename;
	if(!move_uploaded_file($img[&quot;tmp_name&quot;],$newfile)) return false;
	
	return $newfile;

}
?&gt;</pre>
</blockquote>
<p>以上代码，对输入类型也做了判断，看了没有问题。但是问题，确恰恰出现在对获取的用户名变量检测上面。直接获取传入用户名，然后存为文件。 有朋友会说：<strong>这些文件名都是我电脑里面存在的，文件名格式都受限于操作系统对文件名定义。 </strong>但是，需要注意是，对于$_FILES里面获取变量，是直接来自http request请求。它跟普通获取其它get,post变量一样。 因此，别有用心的人，往往会自己模拟浏览器，给服务器发送一个特殊文件名。然后，让存文件时候，能够正常保存为自己格式。</p>
<p>前些年，”\0” 在字符串中，保存为文件，会自动截断后面内容。 如：$filename 构造为：”a.php\0.jpg” ，我们想想，将会变成怎么样？</p>
<p>$newfile = “upload/a.php\0.jpg” 因为，对扩展名验证，最右边”.”后面字符是jpg ，是允许图片格式。 但是，我们一以该文件名，保存。 发现磁盘会在upload目录下面生成a.php ，\0后面所有字符，被自动截断。</p>
<p>该漏洞，风靡一时。当时几乎大多数上存网站都有漏洞。一时，很多平台关闭了上存。其实，根本原因就在此。我们拿到文件名，自己作为最终生成文件名保存了。&#160; 好的方法，是<strong>自己随机生成文件名+读取扩展名 。</strong>这样可以组织输入特殊字符，在进行文件保存时候，被抛弃或截断了。</p>
<p>php4时代这个漏洞可以利用，到php5时代，生成的变量文件名值中，会自动过滤掉”\0” ，这样无论用户构造怎么样的特殊”\0”用户名，都会被截断。 但是 ，目前这类漏洞，在asp,jsp 等站点。还经常有出现。老版本的php站点也会经常出现。</p>
<p>&#160;</p>
<p>好了，今天先到这里，后面还有2种其它常见方法，后面给出！欢迎交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/136.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web上存漏洞及原理分析、防范方法</title>
		<link>http://blog.chacuo.net/108.html</link>
		<comments>http://blog.chacuo.net/108.html#comments</comments>
		<pubDate>Thu, 30 May 2013 15:42:34 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web安全]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[上存漏洞]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=108</guid>
		<description><![CDATA[网站提供上存功能，是很多站点经常会有功能，商城，论坛还有常见一些网盘站点。常见互联网上面，我们也是经常听说，某 [...]]]></description>
				<content:encoded><![CDATA[<p>网站提供上存功能，是很多站点经常会有功能，商城，论坛还有常见一些网盘站点。常见互联网上面，我们也是经常听说，某某站点出现上存漏洞，某某开源项目有上存漏洞。 从互联网开始出现动态程序，上存漏洞像幽灵一样，频繁的出现在各种系统中。为什么，一个上存漏洞会这么频繁出现呢。而且，有些系统反复修补，多次还没有修补成功！其实主要问题，还是出现在上存原理上面。我们先看看，上存过程。</p>
<ul>
<li>
<h3><span style="font-weight: bold">网站上存过程分析</span></h3>
</li>
</ul>
<blockquote><div>
<div>
<pre><span style="color: #0000ff">&lt;?</span>php
<a style="color: #ffa500" href="http://www.php.net/header">header</a>(&quot;<span style="color: #8b0000">Content-type: text/html; charset=utf-8</span>&quot;); 
<a style="color: #0000ff" href="http://www.php.net/if">if</a>($_FILES)
{
	<a style="color: #0000ff" href="http://www.php.net/echo">echo</a> '<span style="color: #8b0000">&lt;pre&gt;</span>';
	<a style="color: #ffa500" href="http://www.php.net/var_dump">var_dump</a>($_FILES);
	<a style="color: #0000ff" href="http://www.php.net/echo">echo</a> '<span style="color: #8b0000">&lt;/pre&gt;</span>';
}
<span style="color: #0000ff">?&gt;</span>
<span style="color: #0000ff">&lt;</span><span style="color: #800000">form</span> <span style="color: #ff0000">action</span>=<span style="color: #0000ff">&quot;&quot;</span> <span style="color: #ff0000">enctype</span>=<span style="color: #0000ff">&quot;multipart/form-data&quot;</span> <span style="color: #ff0000">method</span>=<span style="color: #0000ff">&quot;POST&quot;</span><span style="color: #0000ff">&gt;</span>
<span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">type</span>=<span style="color: #0000ff">&quot;file&quot;</span> <span style="color: #ff0000">name</span>=<span style="color: #0000ff">&quot;txt&quot;</span> <span style="color: #ff0000">size</span>=<span style="color: #0000ff">&quot;50&quot;</span><span style="color: #0000ff">&gt;</span>
<span style="color: #0000ff">&lt;</span><span style="color: #800000">input</span> <span style="color: #ff0000">name</span>=<span style="color: #0000ff">&quot;Submit&quot;</span> <span style="color: #ff0000">type</span>=<span style="color: #0000ff">&quot;submit&quot;</span> <span style="color: #ff0000">value</span>=<span style="color: #0000ff">&quot;提交&quot;</span> <span style="color: #0000ff">&gt;</span>
<span style="color: #0000ff">&lt;/</span><span style="color: #800000">form</span><span style="color: #0000ff">&gt;</span></pre>
</p></div>
<div></div>
</p></div>
</blockquote>
<p>&#160;</p>
<p>以上是个简单测试例子，我们看看</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/05/image22.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/05/image_thumb22.png" width="738" height="459" /></a></p>
<p><strong>我们来分析下：</strong></p>
<p>name来自 上存时候选择文件名称</p>
<p>type 是文件类型， 这个类型那里来的呢？呵呵，这里非常关键的。 很多时候，很多同人会认为，这个是服务器自动判断生成的。 如果是这样想，觉得也有可能。 php 封装了上存，它自带类库好像可以的。&#160; 但是，反过来想想，你随便选择个什么格式文件，都会有格式类型。这样一想，我们推断这个值，可能也来自用户输入的。 我们来抓包看看我们类型。</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/05/image23.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/05/image_thumb23.png" width="856" height="334" /></a></p>
<p><strong>type值 也来自，用户输入值了。</strong></p>
<p>size来自程序计算上存文件大小，这个是自动计算的。 相比我们都清楚的。</p>
<h3></h3>
<h3></h3>
<ul>
<li>
<h3><span style="font-weight: bold">你说这么多有啥样呢？</span></h3>
</li>
</ul>
<p>想必有朋友开始问了，我上面分析上存文件格式 ，跟开发出现漏洞有什么关联呢。 其实，我们想想，上面说的，一个文件名称name属性，以及文件类型type属性。 在我们上存文件，后端处理时候，会经常用到的。 作为开发者，在使用这2个变量，一定要继续执行“<strong>一切输入代码是有害的</strong>”原则。你在使用时候，要把它当作，跟其它get,post 获取变量一样处理。 要检测，过滤一切输入变量。</p>
<p>我们经常做功能是，限定用户输入必须是某种格式文件，然后保存为该格式。分析到这里，下面有很多需要继续分析地方，今天先提出大纲。接下来会分析这样常见3类上存漏洞。</p>
<p><span style="text-decoration: underline">1. 使用用户文件名，生成文件，特殊字符过滤不严格，导致文件生成出现漏洞</span></p>
<p><span style="text-decoration: underline">2.移动文件目录时候，由于采用用户传入的文件名拼接，生成到错误目录</span></p>
<p><span style="text-decoration: underline">3.相信用户输入type 类型，直接将用户文件名保存为文件</span></p>
<p>&#160;</p>
<p>好了，下一篇我会举例逐步分析这3种常见漏洞，欢迎朋友们提出你的观点，与我交流！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/108.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>获取用户Ip地址通用方法常见安全隐患(HTTP_X_FORWARDED_FOR)</title>
		<link>http://blog.chacuo.net/98.html</link>
		<comments>http://blog.chacuo.net/98.html#comments</comments>
		<pubDate>Tue, 28 May 2013 15:27:51 +0000</pubDate>
		<dc:creator>程默</dc:creator>
				<category><![CDATA[web安全]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://blog.chacuo.net/?p=98</guid>
		<description><![CDATA[分析过程 这个来自一些项目中，获取用户Ip，进行用户操作行为的记录，是常见并且经常使用的。 一般朋友，都会看到 [...]]]></description>
				<content:encoded><![CDATA[<ul>
<li>
<h3><span style="font-weight: bold;">分析过程</span></h3>
</li>
</ul>
<p>这个来自一些项目中，获取用户Ip，进行用户操作行为的记录，是常见并且经常使用的。 一般朋友，都会看到如下通用获取IP地址方法。</p>
<blockquote>
<pre>function getIP() { 
	if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { 
		$realip = $_SERVER['HTTP_X_FORWARDED_FOR']; 
	} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { 
		$realip = $_SERVER['HTTP_CLIENT_IP']; 
	} else { 
		$realip = $_SERVER['REMOTE_ADDR']; 
		} 
		return $realip; 
	}</pre>
<pre></pre>
</blockquote>
<p>这个是网上常见获取，ip函数，用这些值获取IP,我们首先要弄清楚，这些数据是从那个地方传过来的。</p>
<ul>
<li>
<h3><span style="font-weight: bold;">IP获取来源</span></h3>
</li>
</ul>
<p>1.&#8217;REMOTE_ADDR&#8217;  是远端IP，默认来自tcp 连接是，客户端的Ip。可以说，它最准确，确定是，只会得到直接连服务器客户端IP。如果对方通过代理服务器上网，就发现。获取到的是代理服务器IP了。</p>
<p>如：a-&gt;b(proxy)-&gt;c  ,如果c 通过&#8217;REMOTE_ADDR&#8217; ，只能获取到b的IP,获取不到a的IP了。</p>
<p><strong>另外:</strong>该IP想篡改将很难实现，在传递知道生成php server值，都是直接生成的。</p>
<p>2.&#8217;HTTP_X_FORWARDED_FOR&#8217;，&#8217;HTTP_CLIENT_IP&#8217; 为了能在大型网络中，获取到最原始用户IP，或者代理IP地址。对HTTp协议进行扩展。定义了实体头。</p>
<p>HTTP_X_FORWARDED_FOR = clientip,proxy1,proxy2  所有IP用”,”分割。 HTTP_CLIENT_IP 在高级匿名代理中，这个代表了代理服务器IP。既然是http协议扩展一个实体头，并且这个值对于传入端是信任的，信任传入方按照规则格式输入的。以下以x_forword_for例子加以说明，正常情况下，这个值变化过程。</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/05/image18.png"><img style="background-image: none; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/05/image_thumb18.png" width="656" height="314" border="0" /></a></p>
<p>&nbsp;</p>
<ul>
<li>
<h3><span style="font-weight: bold;">分析Bug风险点：</span></h3>
</li>
</ul>
<p>通过刚刚分析我们发现，其实这些变量，来自http请求的：x-forword-for字段，以及client-ip字段。 正常代理服务器，当然会按rfc规范来传入这些值。但是，当一个用户直接构造该x-forword-for值，发送给用户用户，那将会怎么样呢？</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/05/image19.png"><img style="background-image: none; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/05/image_thumb19.png" width="633" height="298" border="0" /></a>图（1）</p>
<p>第2步，修改x-forword-fox值，我们看看结果</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/05/image20.png"><img style="background-image: none; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/05/image_thumb20.png" width="691" height="528" border="0" /></a></p>
<p>&nbsp;</p>
<p>第三步，我们再修改下看看会怎么样？</p>
<p><a href="http://blog.chacuo.net/wp-content/uploads/2013/05/image21.png"><img style="background-image: none; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" alt="image" src="http://blog.chacuo.net/wp-content/uploads/2013/05/image_thumb21.png" width="751" height="571" border="0" /></a></p>
<p>&nbsp;</p>
<p>哈哈，看到上面结果没，x-forwarded-for不光可以自己设置值，而且可以设置任意格式值。 这样一来，好比就直接有一个可以写入任意值的字段。并且服务器直接读取，或者写入数据库，或者做显示。它将带来危险性，跟一般对入输入没有做任何过滤检测，之间操作数据源结果一样。 并且容易带来隐蔽性。</p>
<ul>
<li>
<h3><span style="font-weight: bold;">结论：</span></h3>
</li>
</ul>
<p>上面getip函数，除了客户端可以任意伪造IP，并且可以传入任意格式IP。 这样结果会带来2大问题，其一，如果你设置某个页面，做IP限制。 对方可以容易修改IP不断请求该页面。 其二，这类数据你如果直接使用，将带来SQL注册，跨站攻击等漏洞。至于其一，可以在业务上面做限制，最好不采用IP限制。 对于其二，这类可以带来巨大网络风险。我们必须加以纠正。</p>
<p>需要对getip 进行修改，得到安全的getip函数。</p>
<p>这类问题，其实很容易出现，以前我就利用这个骗取了大量伪装投票。有它的隐蔽性，其实只要我们搞清楚了，某些值来龙去脉的话。理解了它的原理，修复该类bug将是非常容易。</p>
<p>题外话，做技术，有三步，先要会做，会解决；后要思考为什么要这么做，原因原理是什么；最后是怎么样做，有没有其它方法。多问问自己，你发现距离技术真理越来越近。你做事会越来越得心应手的！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.chacuo.net/98.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
