<?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>Apex[有所思,有所志] &#187; 代码人生</title>
	<atom:link href="http://apex.ncksoft.com/archives/category/coder/feed" rel="self" type="application/rss+xml" />
	<link>http://apex.ncksoft.com</link>
	<description>日有所思，夜有所志</description>
	<lastBuildDate>Sat, 06 Feb 2010 18:12:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>当遇到C4995警告时该怎么办？</title>
		<link>http://apex.ncksoft.com/archives/293</link>
		<comments>http://apex.ncksoft.com/archives/293#comments</comments>
		<pubDate>Sat, 06 Feb 2010 18:12:04 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[代码人生]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[VC]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=293</guid>
		<description><![CDATA[使用Visual Studio 2008写代码时，编译时遇到警告：
1&#62;d:\program\msvs2008\vc\include\cstdio(49) : warning C4995: 'gets': name was marked as #pragma deprecated
1&#62;d:\program\msvs2008\vc\include\cstdio(53) : warning C4995: 'sprintf': name was marked as #pragma deprecated
1&#62;d:\program\msvs2008\vc\include\cstdio(56) : warning C4995: 'vsprintf': name was marked as #pragma deprecated
1&#62;d:\program\msvs2008\vc\include\cstring(22) : warning C4995: 'strcat': name was marked as #pragma deprecated
1&#62;d:\program\msvs2008\vc\include\cstring(23) : warning C4995: 'strcpy': name was marked as #pragma deprecated
1&#62;d:\program\msvs2008\vc\include\cwchar(36) : warning [...]]]></description>
			<content:encoded><![CDATA[<p>使用Visual Studio 2008写代码时，编译时遇到警告：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">1&gt;d:\program\msvs2008\vc\include\cstdio(49) : warning C4995: 'gets': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cstdio(53) : warning C4995: 'sprintf': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cstdio(56) : warning C4995: 'vsprintf': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cstring(22) : warning C4995: 'strcat': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cstring(23) : warning C4995: 'strcpy': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cwchar(36) : warning C4995: 'swprintf': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cwchar(37) : warning C4995: 'vswprintf': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cwchar(39) : warning C4995: 'wcscat': name was marked as #pragma deprecated</li>
<li>1&gt;d:\program\msvs2008\vc\include\cwchar(41) : warning C4995: 'wcscpy': name was marked as #pragma deprecated</li></ol></div>
<p>意思是说，某个函数已经被标记为过时了，最好不要用，在将来的版本中，该函数可能就没有了，不存在了。</p>
<p>奇怪的是，代码里面并没有使用这些函数啊。但是先不考虑这个了，还是看看如何解决吧。对于编译器警告，当然可以用 #pragma warning(disable: xxxx ) 的语法将其禁止掉，这样编译时编译器就不会在那里唧唧歪歪了。在网上查找此类问题，基本上都是这样说的。</p>
<p>然后仔细想想，关闭这个警告并不正常，因为这样一来，所有过时的函数都不会再警告了，而我们可能是需要这个警告的，像是对于strcpy这种超常用的函数，考虑到安全性（应对缓冲区溢出攻击），我们的确应该使用其安全版本，例如strcpy就有对应的StringCchCopy/StringCbCopy这样的函数，如果关闭了此警告，我们就可能在代码中不小心写下strcpy，而不是其对应的安全版本（当然，strcpy等函数是特例，关闭C4995警告后，仍然会有其他警告，下面有说明）。</p>
<p>所以，考察上述几个函数，我们知道其函数声明所在的头文件，这些头文件中的函数应该都不会用到，所以可以用另一种方式来避免引入这些头文件：</p>
<p>在你的工程的预编译头文件（一般来说，就是stdafx.h）中，在 #pragma once 一行后面加上下列三行：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span class="hl-prepro">#define</span><span class="hl-code"> </span><span class="hl-identifier">_CSTDIO_</span><span class="hl-prepro"></span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-prepro">#define</span><span class="hl-code"> </span><span class="hl-identifier">_CSTRING_</span><span class="hl-prepro"></span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-prepro">#define</span><span class="hl-code"> </span><span class="hl-identifier">_CWCHAR_</span></li></ol></div>
<p>这样，编译器就不会再加载 cstdio / cstring / cwchar 这几个头文件了。</p>
<p><strong>P.S.</strong><br />
使用 #pragma warning(disable: xxxx) 这种方式关闭警告后，如果代码里面用到了 strcpy 这样的函数，编译器会报另一个警告：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">1&gt;e:\work\ncksoft\test\main.cpp(126) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.</li>
<li>1&gt;&nbsp; &nbsp; &nbsp; &nbsp; d:\program\msvs2008\vc\include\string.h(74) : see declaration of 'strcpy'</li></ol></div>
<p>所以我们仍然可以得到想要的警告信息。</p>
<p><strong>再 P.S.</strong><br />
如果在代码中使用 #pragma deprecated( name_of_deprecated ) ，就会在编译时报 C4995 警告，而使用下面的方法，则会报 C4996 警告：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span class="hl-identifier">__declspec</span><span class="hl-brackets">(</span><span class="hl-identifier">deprecated</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-types">void</span><span class="hl-code"> </span><span class="hl-identifier">foo</span><span class="hl-brackets">(</span><span class="hl-types">int</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;&nbsp; </span><span class="hl-comment">// ...</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span></li></ol></div>
<p><strong>再 再 P.S.</strong><br />
我很讨厌那些将警告信息视作无物的程序员，一点美感都没有！</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/293/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PHP网站提速</title>
		<link>http://apex.ncksoft.com/archives/279</link>
		<comments>http://apex.ncksoft.com/archives/279#comments</comments>
		<pubDate>Fri, 11 Dec 2009 18:44:59 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[代码人生]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[网站优化]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=279</guid>
		<description><![CDATA[最近在研究网站提速、搜索引擎优化等技术，打算将一些技巧逐步分享，这里先说说提速。
对于基于PHP构建的网站，一个可行的方法是将网络上传输的内容减少。一是压缩，二是如果内容没有发生变化，则不发送内容到客户端，而是让客户端使用缓存的数据。虽然说现在网络速度已经比较快了，但是考虑到网页大部分都是文本内容，压缩率还是相当可观的，一般来说，构成网页的文本内容如HTML/CSS/JS等，使用gzip压缩可以达到60%以上的压缩率。这样，一个简单的网站页面每次访问也可减少60KB以上的网络传输量。而压缩操作速度是很快的，一个100KB的页面文本，压缩耗时在3毫秒以下，基本可以忽略。
我打算先从css/javascript文件入手。下面来看一段代码：

&#19979;&#36733;: index.php&#60;?php
&#160;
// Created by Apex
// http://apex.ncksoft.com/archives/279
&#160;
define('FILE_TYPE_UNKNOWN', 0);
define('FILE_TYPE_CSS', 1);
define('FILE_TYPE_JS', 2);
&#160;
// 这个PHP文件将会放到与css和js文件同一个目录下，方便文件定位
$this_path = dirname( realpath(__FILE__) ).DIRECTORY_SEPARATOR;
&#160;
// 根据URL请求来决定后续发生什么样的header到客户端
$type = FILE_TYPE_UNKNOWN;
$fname = '';
if(isset($_REQUEST['css']))
{
&#160; &#160; $type = FILE_TYPE_CSS;
&#160; &#160; $fname = $_REQUEST['css'];
}
else if(isset($_REQUEST['js']))
{
&#160; &#160; $type = FILE_TYPE_JS;
&#160; &#160; $fname = $_REQUEST['js'];
}
else
{
&#160; &#160; exit();
}
&#160;
// 对参数进行判断
if(empty($fname))
{
&#160; &#160; exit();
}
&#160;
// 指定的文件应该存在，否则什么都不输出
$fname = $this_path . $fname;
if(!is_file($fname))
{
&#160; &#160; exit();
}
&#160;
// 得到文件内容，并获取文件最后修改时间
$output = file_get_contents($fname);
$fmtime = filemtime($fname);
&#160;
// 如果该客户端不是第一次希望获取此文件，则会有如下变量
if(isset($_SERVER[&#34;HTTP_IF_MODIFIED_SINCE&#34;]))
{
&#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>最近在研究网站提速、搜索引擎优化等技术，打算将一些技巧逐步分享，这里先说说提速。</p>
<p>对于基于PHP构建的网站，一个可行的方法是将网络上传输的内容减少。一是压缩，二是如果内容没有发生变化，则不发送内容到客户端，而是让客户端使用缓存的数据。虽然说现在网络速度已经比较快了，但是考虑到网页大部分都是文本内容，压缩率还是相当可观的，一般来说，构成网页的文本内容如HTML/CSS/JS等，使用gzip压缩可以达到60%以上的压缩率。这样，一个简单的网站页面每次访问也可减少60KB以上的网络传输量。而压缩操作速度是很快的，一个100KB的页面文本，压缩耗时在3毫秒以下，基本可以忽略。</p>
<p>我打算先从css/javascript文件入手。下面来看一段代码：<br />
<span id="more-279"></span></p>
<div class="hl-title">&#19979;&#36733;: <a href="http://apex.ncksoft.com/wp-content/plugins/coolcode/coolcode.php?p=279&amp;download=index.php">index.php</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span class="hl-inlinetags">&lt;?php</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// Created by Apex</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-comment">// </span><span class="hl-url">http://apex.ncksoft.com/archives/279</span><span class="hl-comment"></span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-reserved">define</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">FILE_TYPE_UNKNOWN</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-reserved">define</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">FILE_TYPE_CSS</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-number">1</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-reserved">define</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">FILE_TYPE_JS</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-number">2</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 这个PHP文件将会放到与css和js文件同一个目录下，方便文件定位</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-var">$this_path</span><span class="hl-code"> = </span><span class="hl-identifier">dirname</span><span class="hl-brackets">(</span><span class="hl-code"> </span><span class="hl-identifier">realpath</span><span class="hl-brackets">(</span><span class="hl-reserved">__FILE__</span><span class="hl-brackets">)</span><span class="hl-code"> </span><span class="hl-brackets">)</span><span class="hl-code">.</span><span class="hl-reserved">DIRECTORY_SEPARATOR</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 根据URL请求来决定后续发生什么样的header到客户端</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-var">$type</span><span class="hl-code"> = </span><span class="hl-identifier">FILE_TYPE_UNKNOWN</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-var">$fname</span><span class="hl-code"> = </span><span class="hl-quotes">''</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-reserved">isset</span><span class="hl-brackets">(</span><span class="hl-var">$_REQUEST</span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">css</span><span class="hl-quotes">'</span><span class="hl-brackets">]))</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$type</span><span class="hl-code"> = </span><span class="hl-identifier">FILE_TYPE_CSS</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$fname</span><span class="hl-code"> = </span><span class="hl-var">$_REQUEST</span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">css</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">else</span><span class="hl-code"> </span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-reserved">isset</span><span class="hl-brackets">(</span><span class="hl-var">$_REQUEST</span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">js</span><span class="hl-quotes">'</span><span class="hl-brackets">]))</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$type</span><span class="hl-code"> = </span><span class="hl-identifier">FILE_TYPE_JS</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$fname</span><span class="hl-code"> = </span><span class="hl-var">$_REQUEST</span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">js</span><span class="hl-quotes">'</span><span class="hl-brackets">]</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">else</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-reserved">exit</span><span class="hl-brackets">()</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 对参数进行判断</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-reserved">empty</span><span class="hl-brackets">(</span><span class="hl-var">$fname</span><span class="hl-brackets">))</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-reserved">exit</span><span class="hl-brackets">()</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 指定的文件应该存在，否则什么都不输出</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-var">$fname</span><span class="hl-code"> = </span><span class="hl-var">$this_path</span><span class="hl-code"> . </span><span class="hl-var">$fname</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-code">!</span><span class="hl-identifier">is_file</span><span class="hl-brackets">(</span><span class="hl-var">$fname</span><span class="hl-brackets">))</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-reserved">exit</span><span class="hl-brackets">()</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 得到文件内容，并获取文件最后修改时间</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-var">$output</span><span class="hl-code"> = </span><span class="hl-identifier">file_get_contents</span><span class="hl-brackets">(</span><span class="hl-var">$fname</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-var">$fmtime</span><span class="hl-code"> = </span><span class="hl-identifier">filemtime</span><span class="hl-brackets">(</span><span class="hl-var">$fname</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 如果该客户端不是第一次希望获取此文件，则会有如下变量</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-reserved">isset</span><span class="hl-brackets">(</span><span class="hl-var">$_SERVER</span><span class="hl-brackets">[</span><span class="hl-quotes">&quot;</span><span class="hl-string">HTTP_IF_MODIFIED_SINCE</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]))</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-comment">// 这个变量里面放着客户端所缓存的这个文件的最后修改时间</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$checktime</span><span class="hl-code"> = </span><span class="hl-var">$_SERVER</span><span class="hl-brackets">[</span><span class="hl-quotes">&quot;</span><span class="hl-string">HTTP_IF_MODIFIED_SINCE</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$checktime</span><span class="hl-code"> = </span><span class="hl-identifier">strtotime</span><span class="hl-brackets">(</span><span class="hl-var">$checktime</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-comment">// 比较一下时间，如果文件没有改动过，则无需发送文件内容（通过发送304响应码来完成）</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-var">$fmtime</span><span class="hl-code"> &lt;= </span><span class="hl-var">$checktime</span><span class="hl-brackets">)</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="hl-identifier">header</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">HTTP/1.1 304 Not Modified</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="hl-reserved">exit</span><span class="hl-brackets">()</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 一个额外处理，将css文件中的注释全部去掉。如何去掉js的注释，还没有做。 :)</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-identifier">FILE_TYPE_CSS</span><span class="hl-code"> == </span><span class="hl-var">$type</span><span class="hl-brackets">)</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$output</span><span class="hl-code"> = </span><span class="hl-identifier">preg_replace</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">!/\*[^*]*\*+([^/][^*]*\*+)*/!</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-quotes">''</span><span class="hl-code">, </span><span class="hl-var">$output</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 重要：只有服务端的PHP加载了zlib模块，且客户端支持获取gzip压缩数据的情况下，我们才进行压缩</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; !</span><span class="hl-identifier">headers_sent</span><span class="hl-brackets">()</span><span class="hl-code"> &amp;&amp;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-identifier">extension_loaded</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">zlib</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"> &amp;&amp;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-identifier">strstr</span><span class="hl-brackets">(</span><span class="hl-var">$_SERVER</span><span class="hl-brackets">[</span><span class="hl-quotes">&quot;</span><span class="hl-string">HTTP_ACCEPT_ENCODING</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]</span><span class="hl-code">,</span><span class="hl-quotes">&quot;</span><span class="hl-string">gzip</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">)</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-comment">// 9 代表最强压缩</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-var">$output</span><span class="hl-code"> = </span><span class="hl-identifier">gzencode</span><span class="hl-brackets">(</span><span class="hl-var">$output</span><span class="hl-code">, </span><span class="hl-number">9</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-comment">// 告诉客户端我们发送的数据是压缩过的</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-identifier">header</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Content-Encoding: gzip</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-comment">// 下面这个header不太清楚其含义，貌似用于通知缓存服务器或者代理服务器（如果有的话）做某些操作吧，请达人告诉我</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-identifier">header</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Vary: Accept-Encoding</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-comment">// 告诉客户端压缩后的数据长度，因为压缩后的数据是二进制的，客户端需要这个数据来决定接收多少数据后可以结束</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-identifier">header</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Content-Length: </span><span class="hl-quotes">&quot;</span><span class="hl-code">.</span><span class="hl-identifier">strlen</span><span class="hl-brackets">(</span><span class="hl-var">$output</span><span class="hl-brackets">))</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 告诉客户端我们本次发送的数据是什么内容，注意编码格式，如果你的不是utf-8编码，要进行修改</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-identifier">FILE_TYPE_CSS</span><span class="hl-code"> == </span><span class="hl-var">$type</span><span class="hl-brackets">)</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-identifier">header</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">content-type: text/css; charset: utf-8</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">else</span><span class="hl-code"> </span><span class="hl-reserved">if</span><span class="hl-brackets">(</span><span class="hl-identifier">FILE_TYPE_JS</span><span class="hl-code"> == </span><span class="hl-var">$type</span><span class="hl-brackets">)</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-brackets">{</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp; &nbsp; </span><span class="hl-identifier">header</span><span class="hl-code"> </span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">content-type: text/javascript; charset: utf-8</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-brackets">}</span><span class="hl-code"></span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 重要：告诉客户端这个文件的最后修改时间，这样客户端下次访问此文件时，才会将这个时间再发回服务器，以便服务器进行判断</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-identifier">header</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Last-Modified: </span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-identifier">gmdate</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">D, d M Y H:i:s</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-var">$fmtime</span><span class="hl-brackets">)</span><span class="hl-code"> . </span><span class="hl-quotes">'</span><span class="hl-string"> GMT</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-identifier">header</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">Etag: &quot;</span><span class="hl-quotes">'</span><span class="hl-code"> . </span><span class="hl-identifier">md5</span><span class="hl-brackets">(</span><span class="hl-var">$_SERVER</span><span class="hl-brackets">[</span><span class="hl-quotes">'</span><span class="hl-string">REQUEST_URI</span><span class="hl-quotes">'</span><span class="hl-brackets">])</span><span class="hl-code">.</span><span class="hl-quotes">'</span><span class="hl-string">&quot;</span><span class="hl-quotes">'</span><span class="hl-brackets">)</span><span class="hl-code">;</span></li>
<li><span class="hl-code">&nbsp;</span></li>
<li><span class="hl-code"></span><span class="hl-comment">// 将压缩后的数据发回客户端</span><span class="hl-code"></span></li>
<li><span class="hl-code"></span><span class="hl-reserved">echo</span><span class="hl-code"> </span><span class="hl-var">$output</span><span class="hl-code">;</span></li>
<li><span class="hl-code"></span><span class="hl-inlinetags">?&gt;</span></li></ol></div>
<p>我已经尽量在代码中使用注释来说明其工作了。</p>
<p>将这个文件放到保存CSS/Javascript文件的目录下，然后在需要使用原来的css/javascript文件的地方如下调用：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span class="hl-brackets">&lt;</span><span class="hl-reserved">link</span><span class="hl-code"> </span><span class="hl-var">rel</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">stylesheet</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-var">href</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://your.domain.com/css/index.php?css=style.css</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-var">type</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">text/css</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">&gt;</span></li></ol></div>
<p>或者这样：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span class="hl-brackets">&lt;</span><span class="hl-reserved">script</span><span class="hl-code"> </span><span class="hl-var">src</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://your.domain.com/css/index.php?js=common.css</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-var">type</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">text/javascript</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">&gt;</span></li></ol></div>
<p>就可以了。</p>
<p>可能你会问，为什么要这么做？为什么不直接使用Apache的mod_deflate模块来做输出时的压缩呢？原因有三个。</p>
<ol>
<li>缺省安装Apache是不会安装mod_deflate模块的，如果你的代码跑在一台你不能触及Apache设置的主机上，你将不得不用这里的办法；</li>
<li>这样可以让我们在编写代码时，尽量加入注释，以便使得代码自我解释，方便多人（或者自己在将来的某个时刻）进行维护，而注释在输出的时候，可以用PHP字符串处理功能干掉；</li>
<li>更重要的是，我们可以将多个css文件或者多个js文件一次性输出到客户端；</li>
</ol>
<p>太晚了，第三点的详细解释随后补上，睡觉去了~~~zz~~ZZZ</p>
<p><strong>[2009-12-12 继续补充]</strong></p>
<p>我们知道，HTTP通讯协议其实是一个很“昂贵”的协议，每次访问服务器上的单个资源，都需要重新经过一次协议握手，其中客户端向服务端发送的请求数据，还包括cookies的内容，以及很多附加的有用数据。而一个页面一般是由多个资源构成的，例如页面文件本身、css文件、js文件、图片文件等等。我们应该尽量减少资源的数量和体积，来减少客户端与服务端的交互。</p>
<p>考虑到现今的网页，一般都会使用多个css文件来控制页面布局及外观。其实，完全可以将其合并为一个文件，这样客户端也就只需要发送一次请求即可。我们可以采用下面的方法：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span class="hl-brackets">&lt;</span><span class="hl-reserved">link</span><span class="hl-code"> </span><span class="hl-var">rel</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">stylesheet</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-var">href</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">http://your.domain.com/css/index.php?css=layout.css,style.css,color.css</span><span class="hl-quotes">&quot;</span><span class="hl-code"> </span><span class="hl-var">type</span><span class="hl-code">=</span><span class="hl-quotes">&quot;</span><span class="hl-string">text/css</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">&gt;</span></li></ol></div>
<p>这样，我们一次性将服务器上的三个css文件发送给客户端了（当然，代码要略作调整，需要内部分解参数，然后读取三个文件到一个buffer中，再压缩输出，还要考虑最后更新时间采用哪个文件的，等等，不过这都是小问题）。</p>
<p>js文件也可如此处理。</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/279/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>谈谈网银和USB Key (五)</title>
		<link>http://apex.ncksoft.com/archives/273</link>
		<comments>http://apex.ncksoft.com/archives/273#comments</comments>
		<pubDate>Sat, 27 Jun 2009 18:56:04 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[PKI]]></category>
		<category><![CDATA[网银]]></category>
		<category><![CDATA[USB Key]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=273</guid>
		<description><![CDATA[好久没有写日志了，倒不是这段时间没有所思，而是思得太多，做的也更多，也就没有时间写了。好了，言归正传，下面我们接着说说《谈谈网银和USB Key (四)》中最后提到的“带确定按键的USB Key仍然不够安全”的原因。
是的，带确定按键的USB Key可以做到每次使用硬件内部的私有密钥时都是持有者明确授权的（即持有者做了按下确认键的操作），但是不要忘记，你能保证被签名的数据就一定是你想要签名的数据吗？这句话听起来有点绕口，那么我们来举一个例子：
特别注明：本文中所提到的商家、银行、地点、人物等均为举例方便而用，没有任何明确或隐含的意义。如有雷同，那一定是你踩到狗屎了~~~

假如你正在淘宝上买东西，购物车里塞满了满意的商品，终于，你决定购买了，于是开始下订单，但是发现你的淘宝账户上余额不足。这是个小问题，因为我们可以立即使用网上银行转账到淘宝账户上。OK，你来到支付宝，选择已经开通了网上银行功能的银行，然后点击“现在就转账”，终于进入了网上银行转账的页面。
&#8230;&#8230;其实，以上都是废话，因为我们不过是要提到网银转账的页面而已。不过，这可是我使用淘宝的真实流程哦&#8230;&#8230;
在网银的转账页面上，一般需要提供三个信息：你的账户、对方账户以及转账金额。其中，你的账户是你在登陆网银时就隐含提供了，对方账户则需要你填写（如果是向淘宝这样的商家转账，网上支付系统会自动填写），转账金额也要你填写（当然，如果是向一些商家转账，网上支付系统也会自动填写）。现在你小心翼翼的填好了所有的内容，并仔细的检查了三遍，一切无误，可以转账了。于是你点下“转账”按钮，网页上提示：请按USB Key的确认键以继续转账操作。当然，因为一切无误，所以你按下了确认键，然后系统提示你：转账已成功！
好了，现在回到淘宝网站，下单吧~~~ :)  等等，为什么淘宝还是提示你余额不足？！无奈之下你只好给银行客服人员打电话，在核对了你的身份之后，你终于等来了一个噩耗，客服MM用甜美的声音告诉你：对不起，我们的系统记录显示，您刚才确实有一次网上交易的操作，不过对方账号的开户行位于广州，是由一位名为“贺爱客”的先生持有的私人账号。[题外话：招商银行信用卡部的客服MM服务真的是一流，业务熟练，声音甜美，而民生银行方面就稍微逊色一些，一个小问题也要等她跟技术方面确认才能回答，希望这只是个例]
“贺爱客”？！鬼知道这是个什么人物，怎么你的钱就转给他了呢？现在你的脑袋里一片空白~~~~
&#8230;&#8230;好了，不用空白了，让我来告诉你发生了什么事吧！通过远程注入、恶意浏览器插件、函数挂钩等诸多手段，你所填写的数据在准备送给USB Key进行数字签名之前的刹那，被修改了！对方账户不再是淘宝，而是“贺爱客”。然而USB Key本身并无法得知你要给谁转账，它只能机械的等待你确认，然后对传入的数据进行签名。从电脑屏幕上来看，数据一切正常，但是到了USB Key内部，就已经大不一样了。这正是三十六计之中的“偷梁换柱”。咳~~咳咳~~~不要把老祖宗留下来的好东西拿来干坏事啊！
偷梁换柱并不是什么困难的事情，最简单的就是使用浏览器插件。尤其是对于IE这种“公共厕所”级别的浏览器，随便谁都可以过来插一脚。曾经有朋友向我抱怨电脑上网越来越慢了，我检查了一下他的系统，发现IE中加载了几十个插件：三个工具栏插件、十几个用于网上看电影的插件、两个网银用到的插件、四个下载加速插件、PDF阅读插件、金山词霸插件、还有七八个不知道是什么东西的插件。我问他为什么装这么多插件，他还一头雾水的问我，插件是虾米东东？？
难道说，在这样一个饿狼环伺，危险重重的恶劣网络环境下，我们就无法安全的使用网上银行，享受足不出户就能指点天下的便捷吗？
请听下回分解&#8230;
]]></description>
			<content:encoded><![CDATA[<p>好久没有写日志了，倒不是这段时间没有所思，而是思得太多，做的也更多，也就没有时间写了。好了，言归正传，下面我们接着说说<a href="http://apex.ncksoft.com/archives/162">《谈谈网银和USB Key (四)》</a>中最后提到的“带确定按键的USB Key仍然不够安全”的原因。</p>
<p>是的，带确定按键的USB Key可以做到每次使用硬件内部的私有密钥时都是持有者明确授权的（即持有者做了按下确认键的操作），但是不要忘记，你能保证被签名的数据就一定是你想要签名的数据吗？这句话听起来有点绕口，那么我们来举一个例子：</p>
<p><strong>特别注明：</strong>本文中所提到的商家、银行、地点、人物等均为举例方便而用，没有任何明确或隐含的意义。如有雷同，那一定是你踩到狗屎了~~~<br />
<span id="more-273"></span><br />
假如你正在淘宝上买东西，购物车里塞满了满意的商品，终于，你决定购买了，于是开始下订单，但是发现你的淘宝账户上余额不足。这是个小问题，因为我们可以立即使用网上银行转账到淘宝账户上。OK，你来到支付宝，选择已经开通了网上银行功能的银行，然后点击“现在就转账”，终于进入了网上银行转账的页面。</p>
<p>&#8230;&#8230;其实，以上都是废话，因为我们不过是要提到网银转账的页面而已。不过，这可是我使用淘宝的真实流程哦&#8230;&#8230;</p>
<p>在网银的转账页面上，一般需要提供三个信息：你的账户、对方账户以及转账金额。其中，你的账户是你在登陆网银时就隐含提供了，对方账户则需要你填写（如果是向淘宝这样的商家转账，网上支付系统会自动填写），转账金额也要你填写（当然，如果是向一些商家转账，网上支付系统也会自动填写）。现在你小心翼翼的填好了所有的内容，并仔细的检查了三遍，一切无误，可以转账了。于是你点下“转账”按钮，网页上提示：请按USB Key的确认键以继续转账操作。当然，因为一切无误，所以你按下了确认键，然后系统提示你：转账已成功！</p>
<p>好了，现在回到淘宝网站，下单吧~~~ :)  等等，为什么淘宝还是提示你余额不足？！无奈之下你只好给银行客服人员打电话，在核对了你的身份之后，你终于等来了一个噩耗，客服MM用甜美的声音告诉你：对不起，我们的系统记录显示，您刚才确实有一次网上交易的操作，不过对方账号的开户行位于广州，是由一位名为“贺爱客”的先生持有的私人账号。[题外话：招商银行信用卡部的客服MM服务真的是一流，业务熟练，声音甜美，而民生银行方面就稍微逊色一些，一个小问题也要等她跟技术方面确认才能回答，希望这只是个例]</p>
<p>“贺爱客”？！鬼知道这是个什么人物，怎么你的钱就转给他了呢？现在你的脑袋里一片空白~~~~</p>
<p>&#8230;&#8230;好了，不用空白了，让我来告诉你发生了什么事吧！通过远程注入、恶意浏览器插件、函数挂钩等诸多手段，你所填写的数据在准备送给USB Key进行数字签名之前的刹那，被修改了！对方账户不再是淘宝，而是“贺爱客”。然而USB Key本身并无法得知你要给谁转账，它只能机械的等待你确认，然后对传入的数据进行签名。从电脑屏幕上来看，数据一切正常，但是到了USB Key内部，就已经大不一样了。这正是三十六计之中的“<strong>偷梁换柱</strong>”。咳~~咳咳~~~不要把老祖宗留下来的好东西拿来干坏事啊！</p>
<p>偷梁换柱并不是什么困难的事情，最简单的就是使用浏览器插件。尤其是对于IE这种“公共厕所”级别的浏览器，随便谁都可以过来插一脚。曾经有朋友向我抱怨电脑上网越来越慢了，我检查了一下他的系统，发现IE中加载了几十个插件：三个工具栏插件、十几个用于网上看电影的插件、两个网银用到的插件、四个下载加速插件、PDF阅读插件、金山词霸插件、还有七八个不知道是什么东西的插件。我问他为什么装这么多插件，他还一头雾水的问我，插件是虾米东东？？</p>
<p>难道说，在这样一个饿狼环伺，危险重重的恶劣网络环境下，我们就无法安全的使用网上银行，享受足不出户就能指点天下的便捷吗？</p>
<p>请听下回分解&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/273/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>升级WordPress到2.8</title>
		<link>http://apex.ncksoft.com/archives/178</link>
		<comments>http://apex.ncksoft.com/archives/178#comments</comments>
		<pubDate>Mon, 15 Jun 2009 16:41:28 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[WordPress相关]]></category>
		<category><![CDATA[DeepWater]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=178</guid>
		<description><![CDATA[很久都没有更新博客了，实在是最近太忙了。这不，前两天趁着WordPress最新版本2.8正式发布，我终于抽了个时间做了一次系统升级。
没有想到的是，忙中出错，升级后系统后台管理进不去了，即使密码是正确的，登录后也只是显示一个“你没有对应的权限！”就把我打发了。没办法，只好临时备份了一下原来的数据库，然后重新创建了一个新的数据库，总算是可以登陆了。
我是从2.5直接升级到2.7的，后台变化太大了，但是感觉非常的棒。
左思右想，让我一直很喜欢的WordPress不应该出现这么低级的错误啊，升级后不应该不能用了。于是仔细检查升级过程所做的操作，果然发现问题：在修改配置文件的时候，原来的数据库没有设定所用的字符集，后台老版本缺省使用的是拉丁字符集，新版本缺省使用UTF-8字符集。屏蔽字符集设定，切换回旧的数据库，一切正常了，原来的插件都能用，自己设计的主题DeepWater也显示正常，真好。
嗯嗯，经验值涨17点~~~
过段时间有空了，写个脚本，将原来的数据库内容全部转换为UTF-8，以适应世界潮流，哇哈哈哈~~~~~
]]></description>
			<content:encoded><![CDATA[<p>很久都没有更新博客了，实在是最近太忙了。这不，前两天趁着WordPress最新版本2.8正式发布，我终于抽了个时间做了一次系统升级。</p>
<p>没有想到的是，忙中出错，升级后系统后台管理进不去了，即使密码是正确的，登录后也只是显示一个“你没有对应的权限！”就把我打发了。没办法，只好临时备份了一下原来的数据库，然后重新创建了一个新的数据库，总算是可以登陆了。</p>
<p>我是从2.5直接升级到2.7的，后台变化太大了，但是感觉非常的棒。</p>
<p>左思右想，让我一直很喜欢的WordPress不应该出现这么低级的错误啊，升级后不应该不能用了。于是仔细检查升级过程所做的操作，果然发现问题：在修改配置文件的时候，原来的数据库没有设定所用的字符集，后台老版本缺省使用的是拉丁字符集，新版本缺省使用UTF-8字符集。屏蔽字符集设定，切换回旧的数据库，一切正常了，原来的插件都能用，自己设计的主题DeepWater也显示正常，真好。</p>
<p>嗯嗯，经验值涨17点~~~</p>
<p>过段时间有空了，写个脚本，将原来的数据库内容全部转换为UTF-8，以适应世界潮流，哇哈哈哈~~~~~</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/178/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Apache的SSL缓存</title>
		<link>http://apex.ncksoft.com/archives/177</link>
		<comments>http://apex.ncksoft.com/archives/177#comments</comments>
		<pubDate>Sat, 03 Jan 2009 02:29:59 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[PKI]]></category>
		<category><![CDATA[代码人生]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[ssl]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=177</guid>
		<description><![CDATA[自从六年前我从ASP阵营弃暗投明转向PHP阵营之后，就不时的与Apache打交道，Apache的配置也从1.3研究到2.2版。但是有一个问题一直困扰我，而且它不定时的就冒出来打击我一下，让我很是郁闷。
这个问题是这样的：把网站设置为需要进行SSL双向认证（即通过https://的方式访问网站，还需要有客户端数字证书），如果服务端是基于Apache的话，那么客户端（也就是浏览器）每次访问一个页面，对于页面上的每一份资源（一个页面通常包含很多资源，例如被html页面引用的.js/.css文件，页面中的各个图片、flash等等），都需要做一次数字签名。奇怪的是IIS服务器就没有这种情况。
每访问一个资源就做一次数字签名，这是一件恐怖的事情。一般情况下一个html页面都会包含十几个甚至几十个资源（特别是一些装饰用的小图片和一些小图标等等，每个文件也就两三KB，但是也需要进行数字签名），早期使用数字证书的时候基本上都是将数字证书保存在计算机硬盘上，数字签名也是由CPU来进行，一次数字签名也就几个毫秒，看起来影响就不大，但是随着技术的发展，后来都是以USB Key来对数字证书进行存储和运算，为了安全，数字签名就只能USB Key内部进行。试想一下，处理器速度一般就几M，高的也就几十M的USB Key处理芯片，在做数字签名的时候效率比起计算机两三个G的运算速度低了不少，即使经过特别优化，一般的USB Key做一次数字签名也需要十多二十毫秒。这种情况下，每访问一个资源就需要做一次数字签名，在打开一个网页的时候，就会发现有明显的延时，现象就是页面文字都已经显示出来了，而USB Key的指示灯还在狂闪（USB Key上通常有一个指示灯，当USB Key正在工作的时候就会闪烁，以提醒用户），然后才能够看到页面上的图片内容一个一个的显示出来。
这几年里，对于这个问题我一直都不求甚解，当初想通过修改Apache配置来解决，也试图在PHP脚本中加入Keep-alive之类的标记，但是终不得其法，渐渐的也就有了一个错误的认识，那就是Apache无法做到SSL状态的缓存，客户端访问每个SSL资源都必须重新重新经历握手、产生会话密钥等过程，所以每访问一个资源就会做一次数字签名。
这个错误的认识一直延续了好几年，在这几年中，当有人问到我这方面的问题时，我都毫不犹豫的告诉他这是Apache的问题，是出于安全性考虑才这样做的。但是另一方面，在我内心深处，还是隐约觉得事情不应该是这样的。终于，在一次封闭开发的过程中，我弄明白了事情的真相。

前几天因为一个银行的项目，需要我们做一个客户端软件来登陆银行的网银系统，而不是直接使用浏览器。我的任务就是做这个客户端软件。当然，做这样一个客户端并不是很困难的事情，大约封闭开发了四天，客户端就基本完成了。在自我测试的时候，前面所讲的这个问题又一次出现在我面前。
看着漂亮的客户端软件界面（其实就是内嵌一个WebBrowser控件的对话框），再看着登录成功后还一直狂闪的USB Key指示灯，心中越来越郁闷。Apache不会这么弱智的呀，那么弱智的应该是我了。那么再看一遍Apache的文档吧，网上有一份翻译的非常棒的Apache 2.2的文档，是金步国先生翻译的（赞一个先，感谢这样默默无私奉献的人！！！）。在mod_ssl模块的文档中，关于“SSLSessionCache 指令”一段又反复读了几遍。对于“SSLSessionCache”指令，官方解释是“这个指令指定了全局/进程间SSL会话缓存的类型。SSL会话缓存机制(可选的)可以加速对并发HTTPS请求的处理速度。对于同一个服务器进程处理的 HTTP keep-alive连接，OpenSSL自身已经在本地缓存了SSL会话信息。但是由于现代浏览器会使用多个并发连接请求页面内的图片等其他资源，服务器就不得不使用不同的进程来处理这些连接，因此能够在不同进程之间缓存SSL会话信息就有助于避免不必要的握手过程。”也就是说，Apache肯定是支持SSL缓存的。其推荐的方式是使用shm（也就是共享内存方式）来做SSL的状态缓存，再看看Windows版Apache安装后其配置文件中缺省使用的是shmcb的方式（这种方式在文档中并未提及），而我的Apache配置一直使用的是这个缺省配置。
我的天，该不会是shmcb方式是有问题的吧。把shmcb改为shm，果然，问题解决！！！
我不知道该哭还是该笑~~~ 困扰我五、六年的问题就这样改动两个字母就搞定了！
]]></description>
			<content:encoded><![CDATA[<p>自从六年前我从ASP阵营弃暗投明转向PHP阵营之后，就不时的与Apache打交道，Apache的配置也从1.3研究到2.2版。但是有一个问题一直困扰我，而且它不定时的就冒出来打击我一下，让我很是郁闷。</p>
<p>这个问题是这样的：把网站设置为需要进行SSL双向认证（即通过https://的方式访问网站，还需要有客户端数字证书），如果服务端是基于Apache的话，那么客户端（也就是浏览器）每次访问一个页面，对于页面上的每一份资源（一个页面通常包含很多资源，例如被html页面引用的.js/.css文件，页面中的各个图片、flash等等），都需要做一次数字签名。奇怪的是IIS服务器就没有这种情况。</p>
<p>每访问一个资源就做一次数字签名，这是一件恐怖的事情。一般情况下一个html页面都会包含十几个甚至几十个资源（特别是一些装饰用的小图片和一些小图标等等，每个文件也就两三KB，但是也需要进行数字签名），早期使用数字证书的时候基本上都是将数字证书保存在计算机硬盘上，数字签名也是由CPU来进行，一次数字签名也就几个毫秒，看起来影响就不大，但是随着技术的发展，后来都是以USB Key来对数字证书进行存储和运算，为了安全，数字签名就只能USB Key内部进行。试想一下，处理器速度一般就几M，高的也就几十M的USB Key处理芯片，在做数字签名的时候效率比起计算机两三个G的运算速度低了不少，即使经过特别优化，一般的USB Key做一次数字签名也需要十多二十毫秒。这种情况下，每访问一个资源就需要做一次数字签名，在打开一个网页的时候，就会发现有明显的延时，现象就是页面文字都已经显示出来了，而USB Key的指示灯还在狂闪（USB Key上通常有一个指示灯，当USB Key正在工作的时候就会闪烁，以提醒用户），然后才能够看到页面上的图片内容一个一个的显示出来。</p>
<p>这几年里，对于这个问题我一直都不求甚解，当初想通过修改Apache配置来解决，也试图在PHP脚本中加入Keep-alive之类的标记，但是终不得其法，渐渐的也就有了一个错误的认识，那就是Apache无法做到SSL状态的缓存，客户端访问每个SSL资源都必须重新重新经历握手、产生会话密钥等过程，所以每访问一个资源就会做一次数字签名。</p>
<p>这个错误的认识一直延续了好几年，在这几年中，当有人问到我这方面的问题时，我都毫不犹豫的告诉他这是Apache的问题，是出于安全性考虑才这样做的。但是另一方面，在我内心深处，还是隐约觉得事情不应该是这样的。终于，在一次封闭开发的过程中，我弄明白了事情的真相。<br />
<span id="more-177"></span></p>
<p>前几天因为一个银行的项目，需要我们做一个客户端软件来登陆银行的网银系统，而不是直接使用浏览器。我的任务就是做这个客户端软件。当然，做这样一个客户端并不是很困难的事情，大约封闭开发了四天，客户端就基本完成了。在自我测试的时候，前面所讲的这个问题又一次出现在我面前。</p>
<p>看着漂亮的客户端软件界面（其实就是内嵌一个WebBrowser控件的对话框），再看着登录成功后还一直狂闪的USB Key指示灯，心中越来越郁闷。Apache不会这么弱智的呀，那么弱智的应该是我了。那么再看一遍Apache的文档吧，网上有一份翻译的<a href="http://lamp.linux.gov.cn/Apache/ApacheMenu/index.html">非常棒的Apache 2.2的文档</a>，是金步国先生翻译的（赞一个先，感谢这样默默无私奉献的人！！！）。在mod_ssl模块的文档中，关于“SSLSessionCache 指令”一段又反复读了几遍。对于“SSLSessionCache”指令，官方解释是“这个指令指定了全局/进程间SSL会话缓存的类型。SSL会话缓存机制(可选的)可以加速对并发HTTPS请求的处理速度。对于同一个服务器进程处理的 HTTP keep-alive连接，OpenSSL自身已经在本地缓存了SSL会话信息。但是由于现代浏览器会使用多个并发连接请求页面内的图片等其他资源，服务器就不得不使用不同的进程来处理这些连接，因此能够在不同进程之间缓存SSL会话信息就有助于避免不必要的握手过程。”也就是说，Apache肯定是支持SSL缓存的。其推荐的方式是使用shm（也就是共享内存方式）来做SSL的状态缓存，再看看Windows版Apache安装后其配置文件中缺省使用的是shmcb的方式（这种方式在文档中并未提及），而我的Apache配置一直使用的是这个缺省配置。</p>
<p>我的天，该不会是shmcb方式是有问题的吧。把shmcb改为shm，果然，问题解决！！！</p>
<p>我不知道该哭还是该笑~~~ 困扰我五、六年的问题就这样改动两个字母就搞定了！</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/177/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>关于Apache的mod_rewrite模块</title>
		<link>http://apex.ncksoft.com/archives/172</link>
		<comments>http://apex.ncksoft.com/archives/172#comments</comments>
		<pubDate>Mon, 27 Oct 2008 17:58:51 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[代码人生]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mod_rewrite]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=172</guid>
		<description><![CDATA[很久以前写过一篇《Apache的Rewrite模块》，但那时是Mambo内部完成的参数解析，我一直没有花时间去真正搞清楚rewrite机制是如何进行的。最近做网站需要自己来做rewrite，所以又复习了一遍。
将动态网页链接rewriting成静态链接是最保险和稳定的面向搜索引擎优化方式。如果网站想更好地被搜索引擎收录，网站设计除了面向用户友好（User Friendly）外，搜索引擎友好 （Search Engine Friendly）的设计也是非常重要的。进入搜索引擎的页面内容越多，则被用户用不同的关键词找到的几率越大。在Google的算法调查一文中提到一个站点被Google索引页面的数量其实对PageRank也是有一定影响的。由于Google突出的是整个网络中相对静态的部分（动态网页索引量比较小）,链接地址相对固定的静态网页比较适合被Google索引（怪不得很多大网站的邮件列表归档和BLOG按日期归档的文档很容被搜的到），因此很多关于面向搜索引擎URL设计优化(URI Pretty)的文章中提到了很多利用一定机制将动态网页参数变成像静态网页的形式：
比如可以将：
http://www.domain.com/index.php?product=mp3&#038;action=ls
变成：http://www.domain.com/product/mp3/action/ls.html
操作如下：

1. 确保apache的http.conf中加载了mod_rewrite模块(缺省是不加载的)。
2. 确保apache配置中站点目录允许.htaccess重载，即：
	AllowOverride All
   需要注意的是，如果站点目录是在虚拟主机设定中进行的，不要改错了位置。
3. 修改了配置文件后，需要重新启动apache。
4. 在需要进行URL重写的目录下建立.htaccess文件。例如要对整个站点进行重写，则在站点根目录下建立.htaccess文件，假定我们的站点根目录为：
   c:\www\htdocs\test\
而服务器的根目录为
   c:\www\htdocs\
那么需要在c:\www\htdocs\test\目录下建立.htaccess，文件内容如下：
&#60;IfModule mod_rewrite.c&#62;
RewriteEngine On
RewriteBase /test/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /test/index.php [L]
&#60;/IfModule&#62;
当然，如果站点目录就是根目录，则.htaccess文件内容如下：
&#60;IfModule mod_rewrite.c&#62;
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
&#60;/IfModule&#62;
上述重写规则表示：启用URL重写功能，对于以&#8221;RewriteBase&#8221;开始的URL，如果没有找到直接的文件，则将其重写为 /index.php 。
假定我们有如下的目录结构(注：站点根目录为c:\www\htdocs\test\)
  c:\www\htdocs\test\
    &#124;- .htaccess
    &#124;- index.php
  [...]]]></description>
			<content:encoded><![CDATA[<p>很久以前写过一篇<a href="http://apex.ncksoft.com/archives/7">《Apache的Rewrite模块》</a>，但那时是Mambo内部完成的参数解析，我一直没有花时间去真正搞清楚rewrite机制是如何进行的。最近做网站需要自己来做rewrite，所以又复习了一遍。</p>
<p>将动态网页链接rewriting成静态链接是最保险和稳定的面向搜索引擎优化方式。如果网站想更好地被搜索引擎收录，网站设计除了面向用户友好（User Friendly）外，搜索引擎友好 （Search Engine Friendly）的设计也是非常重要的。进入搜索引擎的页面内容越多，则被用户用不同的关键词找到的几率越大。在Google的算法调查一文中提到一个站点被Google索引页面的数量其实对PageRank也是有一定影响的。由于Google突出的是整个网络中相对静态的部分（动态网页索引量比较小）,链接地址相对固定的静态网页比较适合被Google索引（怪不得很多大网站的邮件列表归档和BLOG按日期归档的文档很容被搜的到），因此很多关于面向搜索引擎URL设计优化(URI Pretty)的文章中提到了很多利用一定机制将动态网页参数变成像静态网页的形式：<br />
比如可以将：<br />
http://www.domain.com/index.php?product=mp3&#038;action=ls<br />
变成：http://www.domain.com/product/mp3/action/ls.html</p>
<p>操作如下：<br />
<span id="more-172"></span><br />
1. 确保apache的http.conf中加载了mod_rewrite模块(缺省是不加载的)。<br />
2. 确保apache配置中站点目录允许.htaccess重载，即：<br />
	AllowOverride All<br />
   需要注意的是，如果站点目录是在虚拟主机设定中进行的，不要改错了位置。<br />
3. 修改了配置文件后，需要重新启动apache。<br />
4. 在需要进行URL重写的目录下建立.htaccess文件。例如要对整个站点进行重写，则在站点根目录下建立.htaccess文件，假定我们的站点根目录为：<br />
   c:\www\htdocs\test\<br />
而服务器的根目录为<br />
   c:\www\htdocs\<br />
那么需要在c:\www\htdocs\test\目录下建立.htaccess，文件内容如下：</p>
<p><code>&lt;IfModule mod_rewrite.c&gt;<br />
RewriteEngine On<br />
RewriteBase /test/<br />
RewriteCond %{REQUEST_FILENAME} !-f<br />
RewriteCond %{REQUEST_FILENAME} !-d<br />
RewriteRule . /test/index.php [L]<br />
&lt;/IfModule&gt;</code></p>
<p>当然，如果站点目录就是根目录，则.htaccess文件内容如下：</p>
<p><code>&lt;IfModule mod_rewrite.c&gt;<br />
RewriteEngine On<br />
RewriteBase /<br />
RewriteCond %{REQUEST_FILENAME} !-f<br />
RewriteCond %{REQUEST_FILENAME} !-d<br />
RewriteRule . /index.php [L]<br />
&lt;/IfModule&gt;</code></p>
<p>上述重写规则表示：启用URL重写功能，对于以&#8221;RewriteBase&#8221;开始的URL，如果没有找到直接的文件，则将其重写为 /index.php 。</p>
<p>假定我们有如下的目录结构(注：站点根目录为c:\www\htdocs\test\)<br />
  c:\www\htdocs\test\<br />
    |- .htaccess<br />
    |- index.php<br />
    |<br />
    |- info   (这是一个目录)<br />
    |    |-  .htaccess<br />
    |    \-  index.php<br />
    |<br />
    \- info2<br />
         |- test.html<br />
         \- info.php</p>
<p>其中，c:\www\htdocs\test\.htaccess的文件内容为：<br />
<code>&lt;IfModule mod_rewrite.c&gt;<br />
RewriteEngine On<br />
RewriteBase /test/<br />
RewriteCond %{REQUEST_FILENAME} !-f<br />
RewriteCond %{REQUEST_FILENAME} !-d<br />
RewriteRule . /test/index.php [L]<br />
&lt;/IfModule&gt;</code></p>
<p>而 c:\www\htdocs\test\info\.htaccess的内容为：<br />
<code>&lt;IfModule mod_rewrite.c&gt;<br />
RewriteEngine On<br />
RewriteBase /test/info/<br />
RewriteCond %{REQUEST_FILENAME} !-f<br />
RewriteCond %{REQUEST_FILENAME} !-d<br />
RewriteRule . /info/index.php [L]<br />
&lt;/IfModule&gt;</code></p>
<p>那么会有如下重写结果：</p>
<p>尝试访问： http://www.domain.com/test/aaa/bbb/ccc.html<br />
实际访问： /test/index.php<br />
得到参数： /test/aaa/bbb/ccc.html</p>
<p>尝试访问： http://www.domain.com/test/info/bbb/ccc.html<br />
实际访问： /test/info/index.php<br />
得到参数： /test/info/bbb/ccc.html</p>
<p>尝试访问： http://www.domain.com/test/info2/test.html<br />
实际访问： /test/info2/test.html<br />
得到参数： N/A</p>
<p>尝试访问： http://www.domain.com/test/info2/abcd.html<br />
实际访问： /test/index.php<br />
得到参数： /test/info2/abcd.html</p>
<p>上面的内容中，&#8221;实际访问&#8221;就是$_SERVER['PHP_SELF']，而&#8221;得到参数&#8221;其实就是$_SERVER['REQUEST_URI']。这样，我们可以在PHP脚本中根据一定的规则将参数分离出来。比如说对于http://www.domain.com/test/a/AA/b/BB.html:<br />
  &#8230;<br />
  $urlpath = PHP_SELF反向查找&#8217;/'字符，然后抛弃后面的文件名; (得到: /test/)<br />
  $param = REQUEST_URI &#8211; $urlpath; (得到: a/AA/b/BB.html)<br />
  $param = $param &#8211; &#8216;.html&#8217;; (得到: a/AA/b/BB)<br />
  $params = 用&#8217;/'将$param分割; (得到一个数组)<br />
  用循环合成需要的参数，得到 $a = &#8216;AA&#8217;; $b = &#8216;BB&#8217;;<br />
  使用这些参数<br />
  &#8230;</p>
<p>当然，也可以设计其他的参数规则，例如某个页面有固定的参数形式，则可以：<br />
  http://www.domain.com/test/AA/BB.html<br />
我们要求第一个参数一定是$a，第二个参数一定是$b，效果一样。但是这样的规则设计不可以写成：<br />
  http://www.domain.com/test/BB/AA.html<br />
那样就乱套了。</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/172/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>谈谈网银和USB Key (四)</title>
		<link>http://apex.ncksoft.com/archives/162</link>
		<comments>http://apex.ncksoft.com/archives/162#comments</comments>
		<pubDate>Fri, 18 Jul 2008 17:31:08 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[PKI]]></category>
		<category><![CDATA[网银]]></category>
		<category><![CDATA[USB Key]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=162</guid>
		<description><![CDATA[本文一些内容纯属YY，如有雷同，乃是人品爆发。
好了，各位同学，现在我们已经知道黑客无所不在，无所不用其极，目标就是我们网上银行的存款，或者信用卡里的额度。前文《谈谈网银和USB Key (三)》已经简要描述了目前的USB Key的潜在不安全因素，现在我们就来看看如何应对。
关于键盘木马，有一些“软”的方法可以在一定程度上进行遏止。例如“软键盘”，就是不再让用户通过键盘来输入USB Key的个人识别码(PIN码)，而是在屏幕上显示一个虚拟键盘，用户需要通过鼠标点击虚拟按键来输入PIN码。事实上不仅仅是USB Key的PIN码输入采用这种方式，一些网银在不使用USB Key的，但是又需要更高级别安全性的一些地方，也采用“页面虚拟键盘”的方式，例如建行网银的登录页面就是这样的设计。还有一些USB Key的提供商也在键盘驱动上做文章：黑客不是想截取我的输入吗？好，我让你截个够！当进入PIN码输入状态的时候，底层键盘过滤驱动就自动产生无数的按键信息发送给上层软件，將真正的用户输入淹没在极大量的随机击键事件中，让键盘木马难以得知哪些是真的用户输入，哪些是假的。当然，上层软件知道其中的猫腻，可以从杂乱的数据中滤出真正的用户输入。
然而，这些方法都是治标不治本的，因为要完成持有者身份验证，就要將PIN码发送给USB Key，这PIN码总归会出现在电脑的内存中，这些方法只能够在一定程度上增加黑客破解的难度而已。
好了，我们不说这些小儿科的应对方法了，要真正提高USB Key的安全程度，就需要从USB Key的硬件使用方式上入手。

对付键盘木马这种攻击方式，根本的解决方法就是根本不用输入PIN码。嗯，不输入PIN码，那么USB Key怎么知道我就是合法持有者呢？别着急，我们有生物识别技术啊，说白了，最常见的就是指纹识别了。在USB Key上集成一块指纹扫描装置，当需要验证持有者身份的时候，就刷一下指纹，OK，验证通过，可以转帐了，这比记一个USB Key的PIN码还方便，不是吗。而且，指纹的扫描、特征比对都是在USB Key内部完成，根本不与电脑发生任何关系，这就让黑客无计可施了。这样的“指纹USB Key”已经出现在市场上了，北京农村商业银行的“金凤凰网银”就采用了这样的指纹USB Key。
不过并非只要是指纹USB Key就一定安全，如果USB Key上的指纹扫描与识别没有很好的有机结合的话，其中仍然是有漏洞的，例如，如果把指纹扫描的数据传回电脑，由电脑进行指纹特征信息的比对，或者再由电脑將扫描的数据或者特征信息送回USB Key进行处理，黑客就有可能截取到指纹扫描得到的数据，进行“数据重放式攻击”。所以，安全的USB Key一定是由USB Key自己完成整个指纹扫描、特征值提取与比对的全过程的。
然而，指纹USB Key也有其缺点，就是技术含量高，但是成本也高。就目前为止，国内唯一一家能够提供指纹USB Key的厂商是北京飞天诚信科技有限公司。要想指纹USB Key能够广泛的应用起来，还需要时间。
那么，將键盘和USB Key结合起来，使得PIN码不用通过电脑传到USB Key，不也一样安全吗？是的，带键盘输入的USB Key也比较安全，但是请低头看看你的键盘右侧的数字键区域，只是加入0~9这几个数字键，就需要增加不少的体积，这对于需要满足“随身携带”这一特点的USB Key来说，体积实在是大了些，不够实用。不过我想，随着技术的发展，超薄键盘、折叠式键盘、投影式虚拟键盘可能会改变这一状况。嘿嘿，想想投影式虚拟键盘，有点科幻的味道，不过这一天的到来应该不远了～～～
好了，成本高不合适，体积大也不合适，既然目前没有从根本上解决问题的合适的方法，我们就换个思路吧，不要忘了，一切安全性都是相对的～～～
既然黑客总是能够通过各种手段得到USB Key的PIN码，然后在用户没有发觉的情况下完成网上交易，那么，如果我们能够在每次需要USB Key来证明自己身份的时候，需要用户手工干预一下才能完成验证过程，是不是就能够解决这个“不知不觉中”账户里的钱就不翼而飞的问题呢？事实上这样的USB Key已经出现了，国内的几家主要的USB Key厂商都纷纷推出了这种“按钮USB Key”。这种类型的USB Key比普通USB Key多了一个按键，当需要转帐的时候，就需要用户按一下按键，否则USB Key拒绝使用内置的密钥来证明你的身份(进行数字签名)，也就无法完成网上交易。有了这个按钮式USB Key，你的每一次网上交易就明明白白了：只要有网上交易，一定是有人明确的按了这个按钮，而只要这个USB Key没有丢失，那就一定是你自己干的了。即使黑客得到你的PIN码，他也无法通过网络伸手到你的电脑前按一下这个按钮吧！！
好了，按钮式USB Key，这下安全了～～～
安全了？安全了？我带上黑客的帽子，在一边得意的笑，我得儿意的笑，我得儿意的笑～～～～
欲知“按钮USB Key”为何不安全，又如何应对其安全漏洞，请关注本文连载之五。
]]></description>
			<content:encoded><![CDATA[<p><strong>本文一些内容纯属YY，如有雷同，乃是人品爆发。</strong></p>
<p>好了，各位同学，现在我们已经知道黑客无所不在，无所不用其极，目标就是我们网上银行的存款，或者信用卡里的额度。前文《<a href="http://apex.ncksoft.com/archives/160">谈谈网银和USB Key (三)</a>》已经简要描述了目前的USB Key的潜在不安全因素，现在我们就来看看如何应对。</p>
<p>关于键盘木马，有一些“软”的方法可以在一定程度上进行遏止。例如“软键盘”，就是不再让用户通过键盘来输入USB Key的个人识别码(PIN码)，而是在屏幕上显示一个虚拟键盘，用户需要通过鼠标点击虚拟按键来输入PIN码。事实上不仅仅是USB Key的PIN码输入采用这种方式，一些网银在不使用USB Key的，但是又需要更高级别安全性的一些地方，也采用“页面虚拟键盘”的方式，例如建行网银的登录页面就是这样的设计。还有一些USB Key的提供商也在键盘驱动上做文章：黑客不是想截取我的输入吗？好，我让你截个够！当进入PIN码输入状态的时候，底层键盘过滤驱动就自动产生无数的按键信息发送给上层软件，將真正的用户输入淹没在极大量的随机击键事件中，让键盘木马难以得知哪些是真的用户输入，哪些是假的。当然，上层软件知道其中的猫腻，可以从杂乱的数据中滤出真正的用户输入。</p>
<p>然而，这些方法都是治标不治本的，因为要完成持有者身份验证，就要將PIN码发送给USB Key，这PIN码总归会出现在电脑的内存中，这些方法只能够在一定程度上增加黑客破解的难度而已。</p>
<p>好了，我们不说这些小儿科的应对方法了，要真正提高USB Key的安全程度，就需要从USB Key的硬件使用方式上入手。<br />
<span id="more-162"></span></p>
<p>对付键盘木马这种攻击方式，根本的解决方法就是根本不用输入PIN码。嗯，不输入PIN码，那么USB Key怎么知道我就是合法持有者呢？别着急，我们有生物识别技术啊，说白了，最常见的就是指纹识别了。在USB Key上集成一块指纹扫描装置，当需要验证持有者身份的时候，就刷一下指纹，OK，验证通过，可以转帐了，这比记一个USB Key的PIN码还方便，不是吗。而且，指纹的扫描、特征比对都是在USB Key内部完成，根本不与电脑发生任何关系，这就让黑客无计可施了。这样的“指纹USB Key”已经出现在市场上了，北京农村商业银行的“金凤凰网银”就采用了这样的指纹USB Key。</p>
<p>不过并非只要是指纹USB Key就一定安全，如果USB Key上的指纹扫描与识别没有很好的有机结合的话，其中仍然是有漏洞的，例如，如果把指纹扫描的数据传回电脑，由电脑进行指纹特征信息的比对，或者再由电脑將扫描的数据或者特征信息送回USB Key进行处理，黑客就有可能截取到指纹扫描得到的数据，进行“数据重放式攻击”。所以，安全的USB Key一定是由USB Key自己完成整个指纹扫描、特征值提取与比对的全过程的。</p>
<p>然而，指纹USB Key也有其缺点，就是技术含量高，但是成本也高。就目前为止，国内唯一一家能够提供指纹USB Key的厂商是北京飞天诚信科技有限公司。要想指纹USB Key能够广泛的应用起来，还需要时间。</p>
<p>那么，將键盘和USB Key结合起来，使得PIN码不用通过电脑传到USB Key，不也一样安全吗？是的，带键盘输入的USB Key也比较安全，但是请低头看看你的键盘右侧的数字键区域，只是加入0~9这几个数字键，就需要增加不少的体积，这对于需要满足“随身携带”这一特点的USB Key来说，体积实在是大了些，不够实用。不过我想，随着技术的发展，超薄键盘、折叠式键盘、投影式虚拟键盘可能会改变这一状况。嘿嘿，想想投影式虚拟键盘，有点科幻的味道，不过这一天的到来应该不远了～～～</p>
<p>好了，成本高不合适，体积大也不合适，既然目前没有从根本上解决问题的合适的方法，我们就换个思路吧，不要忘了，<strong>一切安全性都是相对的</strong>～～～</p>
<p>既然黑客总是能够通过各种手段得到USB Key的PIN码，然后在用户没有发觉的情况下完成网上交易，那么，如果我们能够在每次需要USB Key来证明自己身份的时候，需要用户手工干预一下才能完成验证过程，是不是就能够解决这个“<strong>不知不觉中</strong>”账户里的钱就不翼而飞的问题呢？事实上这样的USB Key已经出现了，国内的几家主要的USB Key厂商都纷纷推出了这种“按钮USB Key”。这种类型的USB Key比普通USB Key多了一个按键，当需要转帐的时候，就需要用户按一下按键，否则USB Key拒绝使用内置的密钥来证明你的身份(进行数字签名)，也就无法完成网上交易。有了这个按钮式USB Key，你的每一次网上交易就明明白白了：只要有网上交易，一定是有人明确的按了这个按钮，而只要这个USB Key没有丢失，那就一定是你自己干的了。即使黑客得到你的PIN码，他也无法通过网络伸手到你的电脑前按一下这个按钮吧！！</p>
<p>好了，按钮式USB Key，这下安全了～～～</p>
<p>安全了？安全了？我带上黑客的帽子，在一边得意的笑，我得儿意的笑，我得儿意的笑～～～～</p>
<p>欲知“按钮USB Key”为何不安全，又如何应对其安全漏洞，请关注本文连载之五。</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/162/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>“自制CA”的开发告一段落</title>
		<link>http://apex.ncksoft.com/archives/161</link>
		<comments>http://apex.ncksoft.com/archives/161#comments</comments>
		<pubDate>Wed, 09 Jul 2008 17:33:16 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[PKI]]></category>
		<category><![CDATA[代码人生]]></category>
		<category><![CDATA[CA]]></category>
		<category><![CDATA[OCSP]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=161</guid>
		<description><![CDATA[因为种种原因，需要在公司的外网服务器上架构一个CA(证书认证中心)服务，于是乎，开始找免费开源的CA系统。找来找去，找到两个用得比较广泛的开源CA，一个是OpenCA，一个是EJBCA。前者是使用Perl开发的，后者，顾名思义，是Java开发的。
服务器是FreeBSD 7.0，先上的是OpenCA，是因为不想在服务器上装太多的东西，Perl是必装的，所以第一选择就是基于Perl的OpenCA了。使用FreeBSD的Ports方式安装，结果装的过程中发现有太多依赖的库，虽然这些依赖的库都会自动下载并安装，但是心里已经感觉不爽了。接下来的配置让人头疼不已，花了三天时间也没有搞定。
一怒之下，决定把OpenCA打入冷宫。上EJBCA吧，又是一大堆的东西要装，Java运行环境啦，tomcat啦，等等等等。让人郁闷的是要用到一些Java的加密函数库，还必须手工到sun的网站下一堆额外的东西，心里又是不爽起来。结果发现EJBCA的配置更是让人崩溃，近一个星期下来，一事无成。
我靠，装这两个东西，把我精心打造的服务器搞得乱七八糟。于是决定，自己开发一个CA。套一句话说：我是程序员我怕谁～～～

最后决定基于OpenSSL来开发，给它套上一个网站做前端，使用PHP+MySQL来存储证书和相关数据。经过这段时间工作之余断断续续的开发，终于功能全部实现并测试通过了。其实大概一个月前基本功能就完成了，但是有一个很重要的功能——吊销证书——没有完成，所以搁置在一边，忙别的事情去了，这几天又抽出时间来，將吊销功能完成了。
这个自制的CA，我给它起名叫“nanoCA”，意思是极小的CA，呵呵，下面报告一下功能特点：

在线安装，完成必要的数据库结构创建，生成根证书/服务器证书/超级管理员证书/OCSP响应者证书等；
只能使用管理员证书登录方可进行后台的管理；
多语言支持——全部UTF-8；
可颁发测试证书和正式用户证书，前者立即发放，后者需要在后台管理中人工审核后进行签发；
申请、签发、拒绝签发、吊销等都有邮件通知给证书用户；
可以吊销证书，生成吊销列表；
支持OCSP协议，可实时在线查询证书状态(解决了证书吊销列表的时间差问题)；
支持IE/Firefox在线申请证书；
&#8230;&#8230;

目前还不支持Vista平台上申请证书，是因为Vista下微软的证书申请控件已经全面更新且与XP即以前的系统中所带的证书申请控件不兼容。问题已经明确，解决方法也有了，有时间再加吧。
将来有时间，再加上证书更新的功能，就更完美了。呵呵～～～
]]></description>
			<content:encoded><![CDATA[<p>因为种种原因，需要在公司的外网服务器上架构一个CA(证书认证中心)服务，于是乎，开始找免费开源的CA系统。找来找去，找到两个用得比较广泛的开源CA，一个是OpenCA，一个是EJBCA。前者是使用Perl开发的，后者，顾名思义，是Java开发的。</p>
<p>服务器是FreeBSD 7.0，先上的是OpenCA，是因为不想在服务器上装太多的东西，Perl是必装的，所以第一选择就是基于Perl的OpenCA了。使用FreeBSD的Ports方式安装，结果装的过程中发现有太多依赖的库，虽然这些依赖的库都会自动下载并安装，但是心里已经感觉不爽了。接下来的配置让人头疼不已，花了三天时间也没有搞定。</p>
<p>一怒之下，决定把OpenCA打入冷宫。上EJBCA吧，又是一大堆的东西要装，Java运行环境啦，tomcat啦，等等等等。让人郁闷的是要用到一些Java的加密函数库，还必须手工到sun的网站下一堆额外的东西，心里又是不爽起来。结果发现EJBCA的配置更是让人崩溃，近一个星期下来，一事无成。</p>
<p>我靠，装这两个东西，把我精心打造的服务器搞得乱七八糟。于是决定，自己开发一个CA。套一句话说：我是程序员我怕谁～～～</p>
<p><span id="more-161"></span><br />
最后决定基于OpenSSL来开发，给它套上一个网站做前端，使用PHP+MySQL来存储证书和相关数据。经过这段时间工作之余断断续续的开发，终于功能全部实现并测试通过了。其实大概一个月前基本功能就完成了，但是有一个很重要的功能——吊销证书——没有完成，所以搁置在一边，忙别的事情去了，这几天又抽出时间来，將吊销功能完成了。</p>
<p>这个自制的CA，我给它起名叫“nanoCA”，意思是极小的CA，呵呵，下面报告一下功能特点：</p>
<ul>
<li>在线安装，完成必要的数据库结构创建，生成根证书/服务器证书/超级管理员证书/OCSP响应者证书等；</li>
<li>只能使用管理员证书登录方可进行后台的管理；</li>
<li>多语言支持——全部UTF-8；</li>
<li>可颁发测试证书和正式用户证书，前者立即发放，后者需要在后台管理中人工审核后进行签发；</li>
<li>申请、签发、拒绝签发、吊销等都有邮件通知给证书用户；</li>
<li>可以吊销证书，生成吊销列表；</li>
<li>支持OCSP协议，可实时在线查询证书状态(解决了证书吊销列表的时间差问题)；</li>
<li>支持IE/Firefox在线申请证书；</li>
<li>&#8230;&#8230;</li>
</ul>
<p>目前还不支持Vista平台上申请证书，是因为Vista下微软的证书申请控件已经全面更新且与XP即以前的系统中所带的证书申请控件不兼容。问题已经明确，解决方法也有了，有时间再加吧。</p>
<p>将来有时间，再加上证书更新的功能，就更完美了。呵呵～～～</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/161/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>谈谈网银和USB Key (三)</title>
		<link>http://apex.ncksoft.com/archives/160</link>
		<comments>http://apex.ncksoft.com/archives/160#comments</comments>
		<pubDate>Wed, 02 Jul 2008 16:10:19 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[PKI]]></category>
		<category><![CDATA[网银]]></category>
		<category><![CDATA[USB Key]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=160</guid>
		<description><![CDATA[注：本文涉及USB Key高级安全特性，供有一定网银使用经验及基本网络知识的同学阅读。
前面[谈谈网银和USB Key (二)]已经谈到，有了USB Key，我们的网银就“基本安全”了，那么，使用了USB Key还会有什么安全性的隐患，我们又该如何应对呢？
在进一步阅读之前，请先明确一个事实：一切安全性都是相对的。越是安全的系统，对用户的要求就越高，使用起来就越繁琐。我们只能在安全性与易用性之间找一个平衡点，而这个平衡点也会随着技术的发展朝不同的方向偏移。

安全隐患！
首先我们来看看进行一次利用网银进行网上支付的全过程：

將USB Key连接到计算机上，并打开网银网站；
输入帐号、密码等信息登录网银；
输入转帐的目标账户和金额；
要进行网上支付时，需要输入USB Key的PIN码(即个人识别码)；
网上支付完成。

其中，有可能在打开网银网站的时候就需要输入USB Key的PIN码，这是由网银系统设计决定的。
好了，让我们转变一下思维方式，假定我们现在来扮演海盗，呃，不，扮演黑客吧，我们来看看有什么地方可以侵入这个网银交易系统呢？嗯，我们已知的是，用户的私钥是无法得到的，但是看看，这里有好几个安全隐患：

1. 输入帐号、密码信息；
2. 输入USB Key的PIN码；
3. 通常，在没有关闭浏览器之前，一般不用再次输入USB Key的PIN码。

那么，只要我能够植入一个键盘钩子类型的木马程序，监控用户的键盘输入，就可以得到他的帐号和密码了，同样的，也可以得到USB Key的PIN码了。植入木马的手段很多，例如诱惑用户访问一个嵌入木马的网站，或者发送一封具有诱惑力的邮件(其中嵌入木马)，或者做一些工具软件帮助用户清除病毒(但实际上悄悄的嵌入了自己的木马)，或者將一些软件破解版重新打包供下载，只不过在安装包中加入了木马，甚至可以出一款“Windows XP SP3无限激活版”，让用户下载，结果安装好的系统中就已经具有木马了，嘿嘿，黑客的手段太多了。
好了，假定我们的木马已经进驻用户的电脑了。拿到帐号、密码以及USB Key的PIN码有什么用呢？毕竟我们无法拿到他的USB Key啊，也就没有办法使用他的私钥了。不要着急，让我们守株待兔吧。一旦用户將USB Key插入到电脑中，我们的木马程序第二部分就可以开始工作了，第二部分是以隐藏方式开启一个浏览器，模拟网上交易的全过程，包括填写帐号、密码、转帐金额、提供USB Key的PIN码、确认转帐等等，对于网银服务端来说，根本没有办法区分这是用户的正常操作，还是木马的行为。
当然，编写这样的木马程序需要极高的反向工程能力、系统分析能力以及编程造诣，但既然有这种可能，那么在某个时刻这个可能就会变成现实。啊，我听见你说，我们可以防止键盘钩子，让木马无法获取键盘信息。但是我可以负责任的告诉你，键盘监控是无法彻底免除的，即使你使用驱动层次来首先截取输入，但是木马也可以，甚至木马可以使用网银不能使用的技术：rootkit。可以预见，在终极PK的时候，木马是占上风的。
再看看上述第三点漏洞，这就是一个典型的“安全性与易用性”取平衡点的结果。一旦打开浏览器，输入一次PIN码之后，后续的操作就无需再次输入了，这样可以给用户一个比较好的使用体验。然而，倘若黑客在用户浏览器中嵌入一个BHO，一旦发觉用户成功完成一次转帐操作，就以黑客的帐号为目标帐号再次转帐一笔，瞧，多简单，都不用费心去获取什么帐号密码了。
发觉了这样的潜在攻击方式，大部分网银不得不降低易用性，要求每次转帐操作前，强制进行一次USB Key的PIN码验证，这样虽然增加了用户操作量，但可以有效防止因为转帐完成后忘记关闭浏览器而导致的隐藏攻击。
但无论如何，因为键盘木马的存在，普通的USB Key最终会败下阵来，只不过是时间问题。对了，这里请不要考虑杀毒软件，毕竟目前的杀毒软件都是“后知后觉”的，等一个木马被列入杀软的黑名单时，可能损失已经造成了。我们要讨论的是如何在不安全的环境下安全的完成网上交易。
注，上述攻击方式是理想化的分析，说起来简单，但是实现起来却是非常困难的，所以目前看来，普通的USB Key在一定时间内是可以为网银系统提供必要的安全性的。所以，目前各大银行采用的USB Key完全可以满足普通用户对于电子支付的安全要求，使用USB Key比使用纯文件类型的数字证书在安全性上有本质的提升。
如何应对？
啊，已经写了这么多了，休息，休息一会儿～～～
]]></description>
			<content:encoded><![CDATA[<p><strong>注：本文涉及USB Key高级安全特性，供有一定网银使用经验及基本网络知识的同学阅读。</strong></p>
<p><a href="http://apex.ncksoft.com/archives/144">前面[谈谈网银和USB Key (二)]</a>已经谈到，有了USB Key，我们的网银就<strong>“基本安全”</strong>了，那么，使用了USB Key还会有什么安全性的隐患，我们又该如何应对呢？</p>
<p>在进一步阅读之前，请先明确一个事实：<strong>一切安全性都是相对的</strong>。越是安全的系统，对用户的要求就越高，使用起来就越繁琐。我们只能在安全性与易用性之间找一个平衡点，而这个平衡点也会随着技术的发展朝不同的方向偏移。</p>
<p><span id="more-160"></span><br />
<strong>安全隐患！</strong></p>
<p>首先我们来看看进行一次利用网银进行网上支付的全过程：</p>
<ul>
<li>將USB Key连接到计算机上，并打开网银网站；</li>
<li>输入帐号、密码等信息登录网银；</li>
<li>输入转帐的目标账户和金额；</li>
<li>要进行网上支付时，需要输入USB Key的PIN码(即个人识别码)；</li>
<li>网上支付完成。</li>
</ul>
<p>其中，有可能在打开网银网站的时候就需要输入USB Key的PIN码，这是由网银系统设计决定的。</p>
<p>好了，让我们转变一下思维方式，假定我们现在来扮演海盗，呃，不，扮演黑客吧，我们来看看有什么地方可以侵入这个网银交易系统呢？嗯，我们已知的是，用户的私钥是无法得到的，但是看看，这里有好几个安全隐患：</p>
<ul>
<li>1. 输入帐号、密码信息；</li>
<li>2. 输入USB Key的PIN码；</li>
<li>3. 通常，在没有关闭浏览器之前，一般不用再次输入USB Key的PIN码。</li>
</ul>
<p>那么，只要我能够植入一个键盘钩子类型的木马程序，监控用户的键盘输入，就可以得到他的帐号和密码了，同样的，也可以得到USB Key的PIN码了。植入木马的手段很多，例如诱惑用户访问一个嵌入木马的网站，或者发送一封具有诱惑力的邮件(其中嵌入木马)，或者做一些工具软件帮助用户清除病毒(但实际上悄悄的嵌入了自己的木马)，或者將一些软件破解版重新打包供下载，只不过在安装包中加入了木马，甚至可以出一款“Windows XP SP3无限激活版”，让用户下载，结果安装好的系统中就已经具有木马了，嘿嘿，黑客的手段太多了。</p>
<p>好了，假定我们的木马已经进驻用户的电脑了。拿到帐号、密码以及USB Key的PIN码有什么用呢？毕竟我们无法拿到他的USB Key啊，也就没有办法使用他的私钥了。不要着急，让我们守株待兔吧。一旦用户將USB Key插入到电脑中，我们的木马程序第二部分就可以开始工作了，第二部分是以隐藏方式开启一个浏览器，模拟网上交易的全过程，包括填写帐号、密码、转帐金额、提供USB Key的PIN码、确认转帐等等，对于网银服务端来说，根本没有办法区分这是用户的正常操作，还是木马的行为。</p>
<p>当然，编写这样的木马程序需要极高的反向工程能力、系统分析能力以及编程造诣，但既然有这种可能，那么在某个时刻这个可能就会变成现实。啊，我听见你说，我们可以防止键盘钩子，让木马无法获取键盘信息。但是我可以负责任的告诉你，键盘监控是无法彻底免除的，即使你使用驱动层次来首先截取输入，但是木马也可以，甚至木马可以使用网银不能使用的技术：rootkit。可以预见，在终极PK的时候，木马是占上风的。</p>
<p>再看看上述第三点漏洞，这就是一个典型的“安全性与易用性”取平衡点的结果。一旦打开浏览器，输入一次PIN码之后，后续的操作就无需再次输入了，这样可以给用户一个比较好的使用体验。然而，倘若黑客在用户浏览器中嵌入一个BHO，一旦发觉用户成功完成一次转帐操作，就以黑客的帐号为目标帐号再次转帐一笔，瞧，多简单，都不用费心去获取什么帐号密码了。</p>
<p>发觉了这样的潜在攻击方式，大部分网银不得不降低易用性，要求每次转帐操作前，强制进行一次USB Key的PIN码验证，这样虽然增加了用户操作量，但可以有效防止因为转帐完成后忘记关闭浏览器而导致的隐藏攻击。</p>
<p>但无论如何，因为键盘木马的存在，普通的USB Key最终会败下阵来，只不过是时间问题。对了，这里请不要考虑杀毒软件，毕竟目前的杀毒软件都是“后知后觉”的，等一个木马被列入杀软的黑名单时，可能损失已经造成了。我们要讨论的是如何在不安全的环境下安全的完成网上交易。</p>
<p><strong>注，上述攻击方式是理想化的分析，说起来简单，但是实现起来却是非常困难的，所以目前看来，普通的USB Key在一定时间内是可以为网银系统提供必要的安全性的。</strong>所以，目前各大银行采用的USB Key完全可以满足普通用户对于电子支付的安全要求，使用USB Key比使用纯文件类型的数字证书在安全性上有本质的提升。</p>
<p><strong>如何应对？</strong></p>
<p>啊，已经写了这么多了，休息，休息一会儿～～～</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/160/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>QQ游戏外挂？！</title>
		<link>http://apex.ncksoft.com/archives/156</link>
		<comments>http://apex.ncksoft.com/archives/156#comments</comments>
		<pubDate>Sun, 15 Jun 2008 15:08:21 +0000</pubDate>
		<dc:creator>Apex</dc:creator>
				<category><![CDATA[代码人生]]></category>
		<category><![CDATA[游戏]]></category>

		<guid isPermaLink="false">http://apex.ncksoft.com/?p=156</guid>
		<description><![CDATA[说句老实话，已经有近两年没怎么上QQ了，“没怎么上”的意思是少于十次。但是最近家里来了几个朋友，在我的电脑上安装了QQ，顺带着装了一堆QQ相关的东东，像是超级旋风、QQ游戏、QQ音乐等等。
看她们玩QQ游戏里的“大家来找茬”，感觉蛮有意思的。于是大家一起上阵，开始找茬。这个游戏里面的图片都不是很清晰，而且多数都是大场景，要把所有的不同之处全找出来，还是有一定难度的。
不过，这怎么能难倒我呢，嘿嘿，写个程序搞定它。
首先是分析。两张并列的图片，大小是一样的，要快速标记出不同的地方，可以逐点取颜色，两个图片中位置相同但图片不同的地方，将点重新绘制成红色，而一样的地方，转换为同等亮度的灰度色，这样，就可以立刻得到不同的区域了，一旦不同的区域被标记出来，剩下的事情就是轻移鼠标，点击确认罢了。

OK，想到就做。打开Visual Studio，创建一个工程。我们先要取得这两张图片，这个好说，截屏而已，先截取整个屏幕当前显示内容，然后取得鼠标所在位置的窗口位置和大小，然后从整个屏幕截图中再截取这个窗口的内容，就得到QQ游戏窗口的内容了。不过我们需要的是游戏窗口中的两张并列图片，而这两张图片并不是两个窗口控件，没有办法直接定位，那就手工好了，通过上下左右键，完成第一张和第二张图片的定位，将偏移保存到一个配置文件中，这样下一次就不用再重新定位了。
现在，我得到了两张图片，该逐点取色并比较。喔，天哪，一张图片381&#215;286，需要循环108966次，太慢了。是否有别的途径来快速定位？嗯，想到曾经见过SVN内置的一个文件比较工具，可以很容易的找出两个文本文件中不同部分，而对于图像文件，则使用了一个很有意思的方式来比较：将两个图片叠加显示，位于上面的图片透明度可以调节，这样，当使用鼠标移动透明度调节钮的时候，就能够很容易分辨出不同的位置了。我决定也这么做。
半透明图片，怎么处理？嗯，可以考虑使用CXImage类来处理。不过这么个小东西要引入CXImage，貌似有些得不偿失，用GUI+？嗯，想想有没有别的更简单的方法吧。
那么利用人眼的视觉，就应该可以搞定，就是两张图片交替显示，控制一下不要闪烁就可以了。这个办法好，实现起来非常简单，很快就搞定了，呵呵，效果还是蛮不错的。
现在，这个辅助程序是这样工作的：进入游戏界面后，利用辅助程序的定位功能，能够获取并记住游戏窗口，然后通过上下左右键来定位第一张和第二张图片，然后保存定位信息，方便下一次使用。游戏开始后，每次出现新的图片，就点击一下显示按钮，两张图片就开始交替显示，哇，不同之处立马分辨出来了。还好用的是这种方式，因为QQ的找茬游戏，每次出现的两张图片与其他关卡的图片可能是不一样大的，而且相对位置也不尽相同，这时只需要用上下左右键重新微调一下就可以了。
呵呵，利器在手，找茬去也～～～
]]></description>
			<content:encoded><![CDATA[<p>说句老实话，已经有近两年没怎么上QQ了，“没怎么上”的意思是少于十次。但是最近家里来了几个朋友，在我的电脑上安装了QQ，顺带着装了一堆QQ相关的东东，像是超级旋风、QQ游戏、QQ音乐等等。</p>
<p>看她们玩QQ游戏里的“大家来找茬”，感觉蛮有意思的。于是大家一起上阵，开始找茬。这个游戏里面的图片都不是很清晰，而且多数都是大场景，要把所有的不同之处全找出来，还是有一定难度的。</p>
<p>不过，这怎么能难倒我呢，嘿嘿，写个程序搞定它。</p>
<p>首先是分析。两张并列的图片，大小是一样的，要快速标记出不同的地方，可以逐点取颜色，两个图片中位置相同但图片不同的地方，将点重新绘制成红色，而一样的地方，转换为同等亮度的灰度色，这样，就可以立刻得到不同的区域了，一旦不同的区域被标记出来，剩下的事情就是轻移鼠标，点击确认罢了。<br />
<span id="more-156"></span></p>
<p>OK，想到就做。打开Visual Studio，创建一个工程。我们先要取得这两张图片，这个好说，截屏而已，先截取整个屏幕当前显示内容，然后取得鼠标所在位置的窗口位置和大小，然后从整个屏幕截图中再截取这个窗口的内容，就得到QQ游戏窗口的内容了。不过我们需要的是游戏窗口中的两张并列图片，而这两张图片并不是两个窗口控件，没有办法直接定位，那就手工好了，通过上下左右键，完成第一张和第二张图片的定位，将偏移保存到一个配置文件中，这样下一次就不用再重新定位了。</p>
<p>现在，我得到了两张图片，该逐点取色并比较。喔，天哪，一张图片381&#215;286，需要循环108966次，太慢了。是否有别的途径来快速定位？嗯，想到曾经见过SVN内置的一个文件比较工具，可以很容易的找出两个文本文件中不同部分，而对于图像文件，则使用了一个很有意思的方式来比较：将两个图片叠加显示，位于上面的图片透明度可以调节，这样，当使用鼠标移动透明度调节钮的时候，就能够很容易分辨出不同的位置了。我决定也这么做。</p>
<p>半透明图片，怎么处理？嗯，可以考虑使用CXImage类来处理。不过这么个小东西要引入CXImage，貌似有些得不偿失，用GUI+？嗯，想想有没有别的更简单的方法吧。</p>
<p>那么利用人眼的视觉，就应该可以搞定，就是两张图片交替显示，控制一下不要闪烁就可以了。这个办法好，实现起来非常简单，很快就搞定了，呵呵，效果还是蛮不错的。</p>
<p>现在，这个辅助程序是这样工作的：进入游戏界面后，利用辅助程序的定位功能，能够获取并记住游戏窗口，然后通过上下左右键来定位第一张和第二张图片，然后保存定位信息，方便下一次使用。游戏开始后，每次出现新的图片，就点击一下显示按钮，两张图片就开始交替显示，哇，不同之处立马分辨出来了。还好用的是这种方式，因为QQ的找茬游戏，每次出现的两张图片与其他关卡的图片可能是不一样大的，而且相对位置也不尽相同，这时只需要用上下左右键重新微调一下就可以了。</p>
<p>呵呵，利器在手，找茬去也～～～</p>
]]></content:encoded>
			<wfw:commentRss>http://apex.ncksoft.com/archives/156/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
