我心匪石,不可转也

《诗经·邶风·柏舟》

天涯海角

泛彼柏舟,亦泛其流。耿耿不寐,如有隐忧。微我无酒,以敖以游。
我心匪鉴,不可以茹。亦有兄弟,不可以据。薄言往愬,逢彼之怒。
我心匪石,不可转也。我心匪席,不可卷也。威仪棣棣,不可选也。
忧心悄悄,愠于群小。觏闵既多,受侮不少。静言思之,寤辟有摽。
日居月诸,胡迭而微?心之忧矣,如匪浣衣。静言思之,不能奋飞。

JavaScript Function bind

JavaScript bind 函数允许返回一个跟源函数一样的绑定函数。绑定函数与源函数区别在与绑定函数的 this 已经被 bind 修改。

函数定义

new Function().bind(this, arg0, arg1…)

代码示例

function sayHello(guest) {
	console.log('Hello ' + guest + ', I am ' + this.age + ' years old');
}
sayHello('Yue');

var me = {
	name: 'Seven',
	age: '24'
};

var sayHi = sayHello.bind(me);
sayHi('Yue');

执行结果

JavaScript bind

尽管没有通过调用成员方法而是直接执行函数 sayHi(‘Yue’),sayHi 内部的 this 仍然指向了对象 me,而不是默认的 window。

从控制台可以看到 sayHi 已经被“编译”为本地方法。

bind 函数的可选参数 arg0、arg1 等是绑定到源函数对应的第0个参数、第一个参数。执行绑定函数时自动传递已绑定的参数。

与 bind 相比,apply 和 call 方法是在函数执行时改变 this,bind 可以理解为在函数定义时改变 this。

apply、bind、call 对比

函数名 参数列表 说明
apply (this_arg, arguments_array) 调用函数,通过 this_arg 替代源函数默认的 this,arguments_array 是传递给函数的参数列表
var A = {
	name: 'A',
	sayHi: function(guest) {
		console.log('Hi ' + guest + ', I am ' + this.name);
	}
}
var me = {name: 'Seven'};
A.sayHi('Yue');
A.sayHi.apply(me, ['Yue']);
bind (this_arg, arg0, arg1…) 创建与源函数函数体一样的绑定函数,并根据 this_arg 和 arg0、arg1 等分别修改绑定函数的 this 和 默认参数
call (this_arg, arg0, arg1…) 调用函数,通过 this_arg 替代源函数默认的 this,arg0、arg1 等是传递给函数的参数列表
var A = {
	name: 'A',
	sayHi: function(guest) {
		console.log('Hi ' + guest + ', I am ' + this.name);
	}
}
var me = {name: 'Seven'};
A.sayHi('Yue');
A.sayHi.call(me, 'Yue');

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 攻击,不能仅仅依靠浏览器帮我们检测,还需要我们有意识地去过滤这些不安全的脚本。

HTML5 新增标签

语义标签

<article> 定义文章
<aside> 定义页面内容之外的内容
<dialog> 定义对话框或窗口
<figcaption> 定义 figure 标题,类似 <fieldset> 的 <legend>
<figure> 定义媒体内容以及标题
<footer> 定义网页或区块的页脚,类似 div.footer
<header> 定义网页或区块的页眉,类似 div.header
<hgroup> 定义区块或标题组合
<nav> 定义导航链接
<section> 定义区块,区块内部具有关联性
<time> 定义日期/时间

多媒体标签

<audio> 定义声音
<canvas> 定义图形
<embed> 定义外部交互内容或插件
<source> 定义媒体源
<track> 定义用在媒体播放器中的文本轨道
<video> 定义视频

应用标签

<command> 定义命令按钮,目前不受支持
<details> 定义元素的细节
<datalist> 定义下拉列表
<meter> 定义预定义范围内的度量
<menu> 定义菜单,在 4.01 中弃用,在 5 中重新定义,目前不受支持
<menuitem> 定义弹出菜单条目
<progress> 定义进度
<summary> 定义 <details> 标题,类似 <fieldset> 的 <legend>
<wbr> 定义可换行的文本

其他标签

<bdi> 定义文本的文本方向,使其脱离其周围文本方向
<keygen> 定义生成密钥
<mark> 定义有记号的文本
<output> 定义输出类型
<ruby> 定义 ruby 注释
<rp> 定义若浏览器不支持 ruby 元素显示的内容
<rt> 定义 ruby 注释的解释