通过 Socket 获取网站 SSL 证书及公钥

通过 php curl 请求网页并不能获取到证书信息,此时需要使用 ssl socket 获取证书内容。

// 创建 stream context
$context = stream_context_create([
    'ssl' => [
        'capture_peer_cert' => true,
        'capture_peer_cert_chain' => true,
    ],
]);

$resource = stream_socket_client("ssl://$domain:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
$cert = stream_context_get_params($resource);

$ssl = $cert['options']['ssl'];
$resource = $ssl['peer_certificate'];

// 网站证书中只有公钥,通过 openssl_pkey_get_details 导出公钥

$ret = [
    'crt' => '',
    'pub' => '',
];

$pkey = openssl_pkey_get_public($resource);
$ret['pub'] = openssl_pkey_get_details($pkey)['key'];

openssl_x509_export($resource, $pem);
$ret['crt'] = $pem;

foreach ($ssl['peer_certificate_chain'] as $resource)
{
    openssl_x509_export($resource, $pem);
    $ret['crt'] .= "\n" . $pem;
}

// 保存 $ret['crt'] 为 domain.crt
// 保存 $ret['pub'] 为 domain.pub

return $ret;

验证证书中的公钥A是否正确,通过私钥导出公钥B,比较两者发现一致。

$domain = 'blog.zhengxianjun.com';
$port = '443';
// ...
$pub_a = $ret['pub'];

$private_key_path = '/conf/ssl/blog.zhengxianjun.com.key';

// 证书没有设置密码,$passphrase 为空字符串
$pkey = openssl_pkey_get_private(file_get_content($private_key_path), $passphrase = '');
$pub_b = openssl_pkey_get_details($pkey)['key'];

// 两者一致
var_dump($pub_a === $pub_b);

函数 stream_socket_client 还有一个用途是当知道服务器 IP 时,能获取到服务器可能可以使用的域名。

$resource = stream_socket_client("ssl://$ip:$port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
$cert = stream_context_get_params($resource);

// 解析 X.509 格式证书
$info = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);

// 获取证书中的可信域名列表
$domain = str_replace('DNS:', '', $info['extensions']['subjectAltName']);

以上可以看到获取网站证书并不能获得私钥。

在一些使用 CDN 的站点,如果使用了 HTTPS 同时又希望使用自有域名,是否需要将自己的私钥提供给 CDN 厂商呢?实际上证书路径与使用者名称(支持 https 的域名)并不需要一致。

也就是使用自有域名并进行 CDN 加速时不需要使用自有的 ssl 证书,只需将自己的 CDN 域名加到厂商证书的域名列表即可。

JavaScript Crypto-JS 使用手册

使用 Crypto-JS 可以非常方便地在 JavaScript 进行 MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密。

基于 Crypto-JS 实现的在线加密解密工具 —— 在线哈希、在线散列 和 在线加密、在线解密

下面讲述如何使用 Crypto-JS。

Crypto-JS 源码托管在 Google Code,当前版本是 3.1。因为一般在国内也无法打开,所以把源代码分享到百度盘:http://pan.baidu.com/s/1bnyIGxT

Crypto-JS 原网址是 https://code.google.com/p/crypto-js/文中的英文描述均是原作者所有,Crypto-JS 采用的授权协议跟 MIT 类似,可以在任何场景放心使用。

文章最末附上 Crypto-JS 文件目录结构。

使用 Crypto-JS 进行哈希、散列

  • md5

引入 md5.js

<script src="cryptojs/rollups/md5.js"></script>

调用 md5 方法

var str = '123456';
CryptoJS.MD5(str);
  • pbkdf2

PBKDF2 is a password-based key derivation function. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can’t be used directly as a cryptographic key, some processing is required.

A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.

引入 pbkdf2.js

<script src="cryptojs/rollups/pbkdf2.js"></script>

调用 pbkdf2 方法

// 官方示例
var str = '123456';
var salt = CryptoJS.lib.WordArray.random(128/8);

var key128Bits = CryptoJS.PBKDF2(str, salt, { keySize: 128/32 });
var key256Bits = CryptoJS.PBKDF2(str, salt, { keySize: 256/32 });
var key512Bits = CryptoJS.PBKDF2(str, salt, { keySize: 512/32 });

var key512Bits1000Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, {
keySize: 512/32,
iterations: 1000
});
  • ripemd160

引入 ripemd160.js

<script src="cryptojs/rollups/ripemd160.js"></script>

调用 ripemd160 方法

var str = '123456';
CryptoJS.RIPEMD160(str);
  • sha 系列:sha1、sha2、sha3…

sha 具有一系列散列算法

The SHA hash functions were designed by the National Security Agency (NSA). SHA-1 is the most established of the existing SHA hash functions, and it’s used in a variety of security applications and protocols. Though, SHA-1’s collision resistance has been weakening as new attacks are discovered or improved.

SHA-256 is one of the four variants in the SHA-2 set. It isn’t as widely used as SHA-1, though it appears to provide much better security.

SHA-512 is largely identical to SHA-256 but operates on 64-bit words rather than 32.
CryptoJS also supports SHA-224 and SHA-384, which are largely identical but truncated versions of SHA-256 and SHA-512 respectively.

SHA-3 is the winner of a five-year competition to select a new cryptographic hash algorithm where 64 competing designs were evaluated.
SHA-3 can be configured to output hash lengths of one of 224, 256, 384, or 512 bits. The default is 512 bits.

引入 sha 相关 js

<script src="cryptojs/rollups/sha1.js"></script>
<script src="cryptojs/rollups/sha3.js"></script>
<script src="cryptojs/rollups/sha224.js"></script>
<script src="cryptojs/rollups/sha256.js"></script>
<script src="cryptojs/rollups/sha384.js"></script>
<script src="cryptojs/rollups/sha512.js"></script>

调用 sha 相关方法

var str = '123456';
CryptoJS.SHA1(str);

var str = '123456';
CryptoJS.SHA3(str);

// 配置输出的哈希长度
CryptoJS.SHA3(str, {outputLength : 224});
CryptoJS.SHA3(str, {outputLength : 256});
CryptoJS.SHA3(str, {outputLength : 384});
CryptoJS.SHA3(str, {outputLength : 512});

var str = '123456';
CryptoJS.SHA224(str);

var str = '123456';
CryptoJS.SHA256(str);

var str = '123456';
CryptoJS.SHA284(str);

var str = '123456';
CryptoJS.SHA512(str);
  • hmac 系列:hmac_md5、hmac_ripemd160、hmac_sha1、hmac_sha3…

引入 hmac 相关 js

<script src="cryptojs/rollups/hmac-sha1.js">
</script>
<script src="cryptojs/rollups/hmac-sha3.js">
</script>
<script src="cryptojs/rollups/hmac-sha224.js">
</script>
<script src="cryptojs/rollups/hmac-sha256.js">
</script>
<script src="cryptojs/rollups/hmac-sha384.js">
</script>
<script src="cryptojs/rollups/hmac-sha512.js">
</script>

调用 hmac 相关 方法

var str = '123456';
var password = 'password';

// Hmac 相关调用前都增加了 Hmac
CryptoJS.HmacMD5(str, password);
CryptoJS.HmacRIPEMD160(str, password);
CryptoJS.HmacSHA1(str, password);
CryptoJS.HmacSHA3(str, password);
CryptoJS.HmacSHA224(str, password);
CryptoJS.HmacSHA256(str, password);
CryptoJS.HmacSHA384(str, password);
CryptoJS.HmacSHA512(str, password);

使用 Crypto-JS 进行加密、解密

Crypto-JS 相关 encrypt 函数会并不直接返回字符串,需要调用返回对象的 toString 方法,或者通过 Crypto-JS 转码才能得到真实的结果。

  • AES

引入 aes.js

<script src="cryptojs/rollups/aes.js"></script>

调用 CryptoJS.AES

// 官方示例, 每次输出的密文都不一样
CryptoJS.AES.encrypt("Message", "Secret Passphrase");

// 正确用法

var str = '123456';
// 密钥 16 位
var key = '0123456789abcdef';
// 初始向量 initial vector 16 位
var iv = '0123456789abcdef';
// key 和 iv 可以一致

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

var encrypted = CryptoJS.AES.encrypt(str, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为字符串
encrypted = encrypted.toString();

// mode 支持 CBC、CFB、CTR、ECB、OFB, 默认 CBC
// padding 支持 Pkcs7、AnsiX923、Iso10126
// 、NoPadding、ZeroPadding, 默认 Pkcs7, 即 Pkcs5

var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

// 引入其他加密模式, 填充模式需要引入对应的 js 文件
/*
cryptojs/components/mode-cfb-min.js
cryptojs/components/mode-ctr-min.js
cryptojs/components/mode-ecb-min.js
cryptojs/components/mode-ofb-min.js
cryptojs/components/pad-ansix923-min.js
cryptojs/components/pad-iso10126-min.js
cryptojs/components/pad-iso97971-min.js
cryptojs/components/pad-nopadding-min.js
*/
  • DES、Triple DES

DES、Triple DES 的调用形式与 AES 一致。

引入 triple.js, DES 和 Triple DES 都定义在 tripledes.js

<script src="cryptojs/rollups/tripledes.js"></script>

调用 CryptoJS.DES, CryptoJS.TripleDES

var str = '123456';
var key = '0123456789abcdef';
var iv = '0123456789abcdef';

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

// DES 加密
var encrypted = CryptoJS.DES.encrypt(str, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为字符串
encrypted = encrypted.toString();

// DES 解密
var decrypted = CryptoJS.DES.decrypt(encrypted, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

// Triple DES 加密
var encrypted = CryptoJS.TripleDES.encrypt(str, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为字符串
encrypted = encrypted.toString();

// Triple DES 解密
var decrypted = CryptoJS.TripleDES.decrypt(encrypted, key, {
	iv: iv,
	mode: CryptoJS.mode.CBC,
	padding: CryptoJS.pad.Pkcs7
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);
  • Rabbit、RC4

Rabbit、RC4 调用方式一致,不支持 mode、padding。

引入 rabbit.js

<script src="cryptojs/rollups/rabbit.js"></script>

调用 CryptoJS.Rabbit

var str = '123456';
var key = '0123456789abcdef';
var iv = '0123456789abcdef';

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

var encrypted = CryptoJS.Rabbit.encrypt(str, key, {
	iv: iv
});

// 转换为字符串
encrypted = encrypted.toString();

var decrypted = CryptoJS.Rabbit.decrypt(encrypted, key, {
	iv: iv
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

引入 rc4.js

<script src="cryptojs/rollups/rc4.js"></script>

调用 CryptoJS.RC4

var str = '123456';
var key = '0123456789abcdef';
var iv = '0123456789abcdef';

key = CryptoJS.enc.Utf8.parse(key);
iv = CryptoJS.enc.Utf8.parse(iv);

var encrypted = CryptoJS.RC4.encrypt(str, key, {
	iv: iv
});

// 转换为字符串
encrypted = encrypted.toString();

var decrypted = CryptoJS.RC4.decrypt(encrypted, key, {
	iv: iv
});

// 转换为 utf8 字符串
decrypted = CryptoJS.enc.Utf8.stringify(decrypted);

Crypto-JS 文件目录结构

  • cryptojs
    • components
      • aes.js
      • cipher-core.js
      • core.js
      • enc-base64.js
      • enc-utf16.js
      • evpkdf.js
      • format-hex.js
      • hmac.js
      • lib-typedarrays.js
      • md5.js
      • mode-cfb.js
      • mode-ctr.js
      • mode-ctr-gladman.js
      • mode-ecb.js
      • mode-ofb.js
      • pad-ansix923.js
      • pad-iso10126.js
      • pad-iso97971.js
      • pad-nopadding.js
      • pad-zeropadding.js
      • pbkdf2.js
      • rabbit.js
      • rabbit-legacy.js
      • rc4.js
      • ripemd160.js
      • sha1.js
      • sha3.js
      • sha224.js
      • sha256.js
      • sha384.js
      • sha512.js
      • tripledes.js
      • x64-core.js
    • rollups
      • aes.js
      • hmac-md5.js
      • hmac-ripemd160.js
      • hmac-sha1.js
      • hmac-sha3.js
      • hmac-sha224.js
      • hmac-sha256.js
      • hmac-sha384.js
      • hmac-sha512.js
      • md5.js
      • pbkdf2.js
      • rabbit.js
      • rabbit-legacy.js
      • rc4.js
      • ripemd160.js
      • sha1.js
      • sha3.js
      • sha224.js
      • sha256.js
      • sha384.js
      • sha512.js
      • tripledes.js

cryptojs/components 目录下的所有文件都会对应一个压缩文件,比如 cryptojs/components/aes.js 同时会有一个 cryptojs/components/aes-min.js 文件。

cryptojs/rollups 目录下的所有文件都已经压缩完毕,每个文件都可以单独调用。

Web安全之X-Frame-Options

为了避免网页被 frame 或者 iframe 嵌套,可以设置 Frame-Options 禁用。

Frame-Options 目前还未完全成为标准,仍需要使用 X-Frame-Options。

X-Frame-Options 值列表

DENY 拒绝在 frame 或 iframe 中加载网页
SAMEORIGIN 允许在同域 frame 和 iframe 中加载网页
ALLOW-FROM uri 允许在指定域下的 frame 和 iframe 中加载网页,支持并不完整

例如在 www.main.com frame-options.php 中增加 X-Frame-Options header,然后在 www.third.com frame.php 中增加 iframe,指向 frame-options.php,效果如下:

Frame-Options

代码示例:

www.main.com

// 文件 frame-options.php
<?php header('X-Frame-Options: DENY');?>
You cannot see this page.

www.third.com

// 文件 frame.php
<iframe src="http://www.main.com/frame-options.php"></iframe>

Web安全之CSRF

CSRF 全称是 Cross-Site Request Forgery,指攻击者盗用了用户的身份,以用户的身份发送恶意请求。

CSRF 攻击流程

  1. User 登录网站 A(存在 CSRF 攻击漏洞的网站)
  2. User 在没有网站 A 的情况下,使用同一个浏览器访问危险网站 B
  3. 网站 B 模拟 User,发送恶意的 GET 或者 POST 请求(通过 iframe、js 等)到网站 A。比如让网站 A 删除用户数据
  4. 网站 A 在没有防范的情况下,破坏或者泄露了用户数据

网站 A 防范 CSRF 攻击的简单方式是在用户提交表单时,增加一个令牌验证。

令牌验证

在网站 A 增加简单令牌

<?php
function gen_csrf_token()
{
	session_start();
	return md5(session_id());
}

function verify_csrf_token($token)
{
	session_start();
	return $token = md5(session_id());
}
?>
<form action="/user/update" method="post">
	<input name="csrf_token" value="<?=gen_csrf_token()?>"/>
	<input name="sex" value="man"/>
	<input type="submit"/>
</form>

当表单提交时,执行 verify_csrf_token 判断是否令牌是否正确,继而认为不是第三方网站伪造的请求。

HTTP_REFERER 验证

验证 http_referer 也能够从一定程度上降低 CSRF 攻击风险。现代浏览器是不允许修改 HTTP_REFERER 头信息的。

Web安全之CSP

CSP 全称是 Content Security Policy,控制浏览器在加载网络资源时,告知浏览器哪些资源是可信的、安全的。可以有效地降低和杜绝 XSS 攻击。

如何产生 XSS 攻击,可以参考 http://blog.zhengxianjun.com/2015/web-security-xss/

有时候即便整个网站增加了 XSS 防注入,也可能在迭代过程中存在遗漏。

浏览器不能区分哪些资源是安全的,一旦下载之后就会执行。(有些浏览器可以识别简单的 XSS 注入)。

CSP 就是为了告诉浏览器哪些资源是可信任的、安全的,通过白名单去加载网络资源和执行。这样即使网页存在 XSS 注入,出现损失的可能性也会大大地降低。

比如:

Content-Security-Policy: script-src https://s.fiaox.com

那么浏览器只会信任来自 s.zhengxianjun.com 的脚本,这样即使网站被注入了第三方站点脚本或者内联,也不会执行,那 XSS 攻击也就失效了。

代码示例:

<?php header('Content-Security-Policy: script-src https://s.fiaox.com');?>
<script type="text/javascript" src="https://code.jquery.com/jquery.js"></script>
// 支持 CSP 则不会加载来自 jquery.com 的脚本

以上代码分别在 IE、Chrome、Firefox 中的效果。

CSP IE

在 IE10 中,似乎没有支持 CSP,jquery.js 被正常加载和执行。这是因为早期 CSP 没有规范,IE 识别 X-Content-Security-Policy,但并不是完整支持。

CSP Chrome

Chrome 正确识别了 CSP,并且说明了原因。

CSP Firefox

Firefox 正确识别了 CSP,并且说明了原因。

CSP 是帮助浏览器创建了一个网络资源白名单。

CSP 规则列表

Content-Security-Policy: script-src 'self' s.zhengxianjun.com;style-src 'self';img-src 'self'
  • 多个指令之间用英文分号隔开;
  • 指令的值不是域名时需要引号引起来;
  • 指令重复以第一个为准。
指令 说明
default-src 定义资源默认加载策略
connect-src 定义 Ajax、WebSocket 等加载策略
font-src 定义 Font 加载策略
frame-src 定义 Frame 加载策略
img-src 定义图片加载策略
media-src 定义 <audio>、<video> 等引用资源加载策略
object-src 定义 <applet>、<embed>、<object> 等引用资源加载策略
script-src 定义 JS 加载策略
style-src 定义 CSS 加载策略
sandbox 值为 allow-forms,对资源启用 sandbox
report-uri 值为 /report-uri,提交日志

以上指令除了 sandbox、report-uri 是比较特殊的值,其余指令可以接收 ‘self’、data、域名 等值。

指令示例

示例 说明
script-src 允许任何资源
script-src ‘none’ 不允许任何资源
script-src ‘self’ 允许同源资源(协议、域名、端口均相同)
script-src ‘unsafe-eval’ 允许动态脚本,如 eval、setTimeout、new Function
script-src ‘unsafe-inline’ 允许内联资源
script-src s.zhengxianjun.com 允许某个域名下的资源
script-src *.zhengxianjun.com 允许子域名下的资源
script-src https 允许 https 资源
script-src https://zhengxianjun.com 允许某个域名下的 https 资源
img-src data 允许 data: 协议资源

report-uri 会接收到一个 post 请求,包含 CSP 阻止的详细信息。

虽然 CSP 能够有效降低 XSS 攻击,但是不要指望它可以完全杜绝 XSS 攻击。

为了让产品能够顺利过渡到 CSP,可以通过 Content-Security-Policy-Report-Only 先收集 CSP 报告,根据报告修正被阻止的正确资源,再启用 CSP。使用了 Content-Security-Policy-Report-Only 则一定要配置 report-uri。

示例:

Content-Security-Policy-Report-Only: script-src 'self'; report-uri https://www.zhengxianjun.com/csp/report

Web安全之P3P

P3P 全称是 The Platform for Privacy Preferences,控制用户在在浏览网页时,如果网页中包含第三方站点资源,是否接受第三方站点设置的 cookie。

举个例子:

user 访问 www.main.com, 该站点加载了第三方网站 www.third.com 的网页(通过iframe)或者静态资源(css, js, img),是否接受 www.third.com 设置的 cookie。

默认情况下不允许保存第三方 cookie,假如第三方站点在 header 中设置了 P3P 相关信息,则可能允许跨域访问隐私数据

IE 浏览器隐私设置:

IE 浏览器第三方 cookie 策略

Chrome 浏览器隐私设置:

Chrome 浏览器第三方 cookie 策略

配合这两幅截图说明第三方 cookie 在 IE、Chrome 中是否有效。两幅截图显示 IE 阻止第三方 cookie,Chrome 接受第三方 cookie。

代码示例:

www.main.com setcookie

// file http://www.main.com/setcookie.php
<script src="http://www.main.com/setcookie.php"></script>
<!-- <iframe src="http://www.main.com/setcookie.php"></iframe> -->

www.third.com setcookie

// header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"');
setcookie('p3p_cookie_key', 'time_' . time(), time() + 60, '/', '.third.com');

www.third.com getcookie

// file http://www.third.com/getcookie.php
echo 'p3p_cookie_key:' . $_COOKIE['p3p_cookie_key'];

访问 http://www.main.com/setcookie.php,网页会通过 iframe 或者 script 访问 http://www.third.com/setcookie.php, 此时浏览器不一定接受来自 www.third.com 的 cookie。也就是立即访问 http://www.third.com/getcookie.php,可能获取不到 cookie 信息。

当 www.third.com setcookie.php 输出 P3P 头信息时:

  1. 访问 http://www.main.com/setcookie.php
  2. 访问 http://www.third.com/getcookie.php 可以获取到 cookie p3p_cookie_key

网页上所有资源浏览器都可以访问,但出于安全考虑,浏览器对此进行了限制,产生一些安全词汇。

P3P Header is present [引用]

CP=”CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”
Compact Policy token is present. A trailing ‘o’ means opt-out, a trailing ‘i’ means opt-in.
CURa Information is used to complete the activity for which it was provided.
ADMa Information may be used for the technical support of the Web site and its computer system.
DEVa Information may be used to enhance, evaluate, or otherwise review the site, service, product, or market.
PSAo Information may be used to create or build a record of a particular individual or computer that is tied to a pseudonymous identifier, without tying identified data (such as name, address, phone number, or email address) to the record. This profile will be used to determine the habits, interests, or other characteristics of individuals for purpose of research, analysis and reporting, but it will not be used to attempt to identify specific individuals.
PSDo Information may be used to create or build a record of a particular individual or computer that is tied to a pseudonymous identifier, without tying identified data (such as name, address, phone number, or email address) to the record. This profile will be used to determine the habits, interests, or other characteristics of individuals to make a decision that directly affects that individual, but it will not be used to attempt to identify specific individuals.
OUR We share information with ourselves and/or entities acting as our agents or entities for whom we are acting as an agent.
BUS Info is retained under a service provider’s stated business practices. Sites MUST have a retention policy that establishes a destruction time table. The retention policy MUST be included in or linked from the site’s human-readable privacy policy.
UNI Non-financial identifiers, excluding government-issued identifiers, issued for purposes of consistently identifying or recognizing the individual. These include identifiers issued by a Web site or service.
PUR Information actively generated by the purchase of a product or service, including information about the method of payment.
INT Data actively generated from or reflecting explicit interactions with a service provider through its site — such as queries to a search engine, or logs of account activity.
DEM Data about an individual’s characteristics — such as gender, age, and income.
STA Mechanisms for maintaining a stateful session with a user or automatically recognizing users who have visited a particular site or accessed particular content previously — such as HTTP cookies.
PRE Data about an individual’s likes and dislikes — such as favorite color or musical tastes.
COM Information about the computer system that the individual is using to access the network — such as the IP number, domain name, browser type or operating system.
NAV Data passively generated by browsing the Web site — such as which pages are visited, and how long users stay on each page.
OTC Other types of data not captured by the above definitions.
NOI Web Site does not collected identified data.
DSP The privacy policy contains DISPUTES elements.
COR Errors or wrongful actions arising in connection with the privacy policy will be remedied by the service.

Web安全之XSS

在 Web 安全领域有一个词汇经常被提到——XSS。简单地说,就是网页被不信任源注入了可执行脚本

比如:

// a.php 文件内容
<?php $email = $_GET['email'];?>
<input type="hidden" name="email" value=<?=$email?>""/>

// 访问 a.php?email=a%40a.com"%20onclick%3D"alert(1)

// 在网页没有采取任何安全策略的情况下会弹出一个对话框

// 最后的火狐浏览器的截图是攻击者希望看到的

以上代码分别在 IE、Chrome、Firefox 中的效果。

XSS IE

IE 会检测可能的跨站脚本操作。

XSS Chrome

Chrome 也会检测 XSS 攻击,说明了为何出现此提示(its source code was found within the request),也说明了如何更好地工作。

XSS Firefox

不是我黑它,真没有,火狐版本 37.0.2。

这个内联的 onload 并没有包含 <script> 标签,但是它仍然可以执行。这个示例中只是弹出一个对话框,可能还有更严重的破坏行为。

为了避免出现 XSS 攻击,不能仅仅依靠浏览器帮我们检测,还需要我们有意识地去过滤这些不安全的脚本。