读软件开发安全之道:概念、设计与实施13Web安全
1. Web安全
1.1. 当蜘蛛网中出现文字时,所有人都说这是个奇迹。但是没有人指出蜘蛛网本身就是一个奇迹
- 1.1.1. E.B.怀特
1.2. 万维网的巨大成功在很大程度上归因于一个明显的事实:无数人对它的原理一无所知,但经常使用它
-
1.2.1. 网络的易用性促使它的用户持续增长
-
1.2.2. 如此复杂的技术融合在一起所取得的这个非凡成就既是福也是祸
1.3. Web是历史上最极端的亡羊补牢的例子
-
1.3.1. 早期的Web设计非常幼稚,没有过多考虑安全性
-
1.3.1.1. 如果早期创新者在过去试图设计一个完全安全的系统,那么这项任务将会非常艰巨,如果他们失败了,所有努力可能永远不会得到任何成果
-
1.3.2. 现代Web是一个标准长期演变的产物,同时被竞争激烈的“浏览器大战”和向后兼容性所困扰
-
1.3.3. 尽管现代Web可以变得安全,但它错综复杂的历史意味着它也非常脆弱
1.4. 微小的失误很容易造成漏洞
- 1.4.1. 漏洞源于细节,一个安全的网站必须做对很多事情
1.5. 在安全框架上的构建要求,这个安全框架会为你处理错综复杂的事务
2. 建立在框架之上
2.1. 借助现代的Web开发工具,构建网站几乎与使用网站一样简单
2.2. 依赖高质量的框架,永远不要忽视框架所提供的保护措施,让有能力的专家来处理所有混乱的细节
-
2.2.1. 一个可靠的框架应该可以使你免受大部分漏洞的影响,但是准确理解框架会做什么以及不做什么也很重要,因为这样你就可以更有效地利用框架
-
2.2.2. 从一开始就选择一个安全的框架也很重要,因为你的代码将深深依赖于它,如果它未能达到你的预期,在将来更换框架会非常痛苦
2.3. 一般准则
-
2.3.1. 选择使用由值得信赖的组织或团队开发的框架,这些组织或团队会积极地开发和维护这个框架,以跟上不断变化的网络技术和实践
-
2.3.2. 在文档中查找明确书写的安全声明
-
2.3.3. 该框架不需要有完美的记录,但响应迟缓或持续存在的问题模式都是危险信号
-
2.3.4. 构建一个小型原型并检查生成的HTML是否拥有正确的转义和引用
-
2.3.5. 构建一个简单的测试平台来试验基本的XSS和CSRF攻击
3. Web安全模型
3.1. Web是一种客户端/服务器技术
-
3.1.1. 双方的安全利益经常存在争议,尤其是考虑到潜在的攻击者会通过互联网入侵
-
3.1.2. 只有在服务器能够很好地提供安全性的情况下,Web才能工作,这样诚信的终端用户才能有机会获得安全的Web体验
3.2. 客户端浏览器的角色
-
3.2.1. 即使Web服务器尝试对客户使用的浏览器类型进行限制,使其只能使用特定的版本,但浏览器可以轻易实现错误表明自己的身份并绕过这类限制
-
3.2.2. 只要服务器是安全的,恶意客户就无法对服务器提供给其他客户的服务造成影响
-
3.2.3. Web服务器过度信任那些不值得信任的客户端浏览器,可能是众多Web安全漏洞的根源
3.3. HTTP
-
3.3.1. HTTP本身是Web的核心
-
3.3.1.1. Web浏览已经成为日常生活的一部分
-
3.3.2. Web浏览总是从一个URL(Uniform Resource Locator,统一资源定位符)开始的
-
3.3.3. HTTP动作所指定的请求
-
3.3.3.1. GET动作会从服务器请求内容
> 3.3.3.1.1. GET请求不会改变服务器的状态
- 3.3.3.2. 客户端会使用POST动作来提交表单或上传文件
> 3.3.3.2.1. POST请求旨在改变服务器的状态
-
3.3.3.3. 如果你严格地遵守标准规则,可以很容易地让你的服务器变得安全
-
3.3.4. 一条与安全相关的“铁则”是不要在URL中嵌入敏感数据,而是使用表单POST请求向服务器发送敏感数据,否则REFERER请求头在暴露请求所在的网页URL时会泄露敏感数据
-
3.3.5. 一个容易犯的错误是在URL中包含用户名
-
3.3.5.1. 即使使用了不透明类型的标识符(比如用户名的散列值),也会泄露信息,因为窃听者能够通过观察,发现两个单独的URL指向同一个用户
3.4. 数字证书和HTTPS
-
3.4.1. 如果你无法获得可靠的专家建议,你可以看看那些主流且值得信赖的网站是怎样做的,并且遵循它们的做法
-
3.4.2. 安全Web浏览的第一个挑战是与正确的服务器进行可靠的通信
-
3.4.2.1. 如果网络正确地路由并传输了这个请求,则请求应该到达预期的服务器
-
3.4.2.2. 攻击者可能会干扰DNS查找、路由或者路由途中任何位置的数据
> 3.4.2.2.1. HTTPS(也称为HTTP over TLS/SSL)是专为缓解这些威胁而开发的协议
- 3.4.2.3. 没有人对使用HTTPS来保护网络金融交易的必要性提出过异议,但主流网站完全采用HTTPS的时间线拉得太长了
> 3.4.2.3.1. 脸书在2013年才完全采用HTTPS
-
3.4.2.4. 很难想出什么理由不将网站设置为仅使用HTTPS
-
3.4.3. HTTPS提供了一个安全的防篡改端到端加密隧道,并且向客户端保证隧道的另一端确实是预期的服务器
-
3.4.3.1. 将这个安全隧道视为用于确认服务器身份的防数据篡改管道
-
3.4.3.2. 攻击者可能会窃听到加密数据,但如果没有密钥的话,他只能看到一堆无意义的比特
-
3.4.3.3. 攻击者可以篡改无保护网络上的数据,但如果使用了HTTPS,任何篡改都会被发现
-
3.4.3.4. 攻击者可以阻止通信的进行,比如在物理上割断电缆,但你可以确保数据总是真实的
-
3.4.4. HTTPS对于确保真实性和完整性也很重要
-
3.4.4.1. HTTPS确保客户端正在与请求URL中指定的真实服务器进行通信,并且它们之间传输的数据不会被窥探或篡改
-
3.4.5. 随着HTTPS和技术环境的成熟,广泛采用HTTPS的最后一个障碍是获得服务器证书的开销
-
3.4.5.1. 尽管大公司能够负担受信任的CA收取的费用,并且会有工作人员负责管理和更新证书,但较小网站的所有者却对这份额外的成本和管理工作犹豫不决
-
3.4.5.2. 受益于电子前线基金会的大力推动和众多行业公司的赞助,非营利组织互联网安全研究小组的产品Let’s Encrypt为全球用户提供了一个免费、自动化和开放的CA
> 3.4.5.2.1. 可以免费向任何网站所有者提供DV(Domain Validation,域验证)证书
> 3.4.5.2.2. DV证书通常是你用来证明网站身份所需的全部内容
> 3.4.5.2.3. DV证书只能证明这个Web服务器的域名已经经过了验证
> 3.4.5.2.4. 随着免费DV证书的激增,其他类型证书的使用前景变得模糊
> 3.4.5.2.4.1. 用户很少关心这种信任的区别,OV和EV证书在技术和法律上的细微差别也比较难以说清
-
3.4.6. 在将Web服务器设置为使用带有证书的HTTPS后,你必须确保它始终使用HTTPS
-
3.4.7. 利用HTTPS选项,让通信双方为加密隧道协商密码套件(cipher suite)
-
3.4.7.1. 最好的防御措施是确保你的HTTPS配置仅运行安全的现代加密算法
-
3.4.8. 为了缓解这类攻击,我们可以始终将HTTP重定向到HTTPS,并且仅为HTTPS使用Web cookie
-
3.4.8.1. 在HTTP响应头中包含Strict-Transport-Security指令,以便浏览器知道该网站始终使用HTTPS
-
3.4.8.2. 要想完全保障HTTPS网页的安全性,它必须仅使用HTTPS
-
3.4.8.3. 意味着服务器上的所有内容(所有脚本、图像、字体、CSS,以及其他引用资源)都应该使用HTTPS
3.5. 同源策略
-
3.5.1. Same Origin Policy,SOP
-
3.5.2. 浏览器会将来自不同网站的资源隔离开(通常通过窗口或标签页),因此这些资源不会相互影响
-
3.5.3. 仅当资源的主机域名和端口号相同时,资源之间才可以进行交互
-
3.5.4. 同源策略适用于脚本和cookie(与一般的同源策略有些许不同),它们都有可能在独立网站之间泄露数据
-
3.5.5. 尽管同源策略阻止了来自其他网站页面中脚本的进入,但网页始终可以随意选择访问不同的网站,并将其内容拉到窗口中
3.6. Web cookie
-
3.6.1. cookie是指服务器要求客户端为其存储在本地的小的数据字符串,客户端会根据后续请求将其提供给服务器
-
3.6.2. 虽然任何客户端都可以篡改自己的cookie,并将自己的会话伪装成其他会话,但如果会话cookie设计得当的话,客户端应该无法伪造有效的会话cookie
-
3.6.3. 并不意味着cookie没有用,cookie可以用来记住客户的偏好、最喜爱的商品或其他详细信息,篡改这些信息不会对商家造成伤害
-
3.6.4. 服务器可以设置会话cookie的过期时间,但由于服务器不能总是依赖于客户来主动执行这个操作,服务器还必须对需要更新的会话cookie的有效性进行限制
-
3.6.5. cookie会受到同源策略的约束,并对子域之间的共享做出明确规定
-
3.6.5.1. 虽然子域可以看到其父域设置的cookie,但不能修改这些cookie
-
3.6.6. 脚本在名义上可以通过DOM访问cookie,但这种便利性会为设法在网页中运行的恶意脚本提供机会以窃取cookie,因此最好通过执行httponly cookie属性来阻止脚本的访问
-
3.6.6.1. HTTPS网站还应该应用secure属性,指示客户端只通过安全隧道发送cookie
-
3.6.7. 向后兼容性与现代安全性之间的紧张关系带来了妥协的解决方案,这也说明了如果一开始没有考虑安全性的话,未来安全性会变得模糊不清
-
3.6.8. HTML5为安全模型添加了很多扩展
-
3.6.8.1. 一个典型的例子是CORS(Cross-Origin Resource Sharing,跨源资源共享),它允许有选择地放宽同源策略的限制,以使其他受信任的网站能够访问数据
-
3.6.8.2. 浏览器也提供了Web存储API,这是用于Web应用程序的一种更现代的客户端侧存储功能,它也受限于同源策略
4. 跨站脚本攻击
4.1. XSS(Cross-Site Scripting,跨站脚本)攻击
4.2. 同源策略提供的隔离是构建安全网站的基础,但如果我们不采取必要的预防措施,这种保护很容易遭到破坏
4.3. XSS攻击是针对Web的注入攻击,它的恶意输入会改变网站的行为,通常会允许运行未经授权的脚本
4.4. XSS漏洞对于攻击者来说并不难发现,因为他们可以轻易地查看网页内容,来了解这个HTML内部的工作原理
- 4.4.1. 攻击者会设法将恶意数据存储在服务器或客户端中
4.5. 基于DOM的XSS攻击,它将HTML DOM作为恶意注入的来源,但其他方面的工作方式大致相同
4.6. 一个安全的Web框架应该内建XSS保护,在这种情况下,只要在框架内你就是安全的
- 4.6.1. 与任何注入漏洞一样,防御机制包含避免任何不受信任的输入进入Web页面,以及有可能发生的恶意行为,或者执行输入验证来确保安全地处理输入
5. 跨站请求伪造
5.1. CSRF(Corss-Site Request Forgery,跨站请求伪造)
5.2. 跨站请求伪造(CSRF,有时缩写为XSRF)是对同源策略基本限制的攻击
5.3. Web框架应该提供CSRF保护,但深入了解底层问题也很有价值,这样你就可以确认保护机制确实有效,并且能够确保不会干扰该机制
5.4. 同源策略对于POST的处理与GET相同,并且POST请求可以修改站点的状态
5.5. 为了防止CSRF攻击,请确保攻击者无法猜测有效的状态更改请求
-
5.5.1. 将每个有效的POST请求都视为一片特殊的雪花,它只能在其预期的使用环境中工作一次
-
5.5.2. 一个简单的方法是在所有表单中包含一个秘密令牌并将其作为隐藏字段,然后检查每个请求中是否包含与给定Web会话相同的秘密令牌
-
5.5.3. 从会话cookie中派生出令牌是一个很好的解决方案
-
5.5.3.1. 检查所必需的信息都可以在POST请求中获得
-
5.5.4. 另一种缓解措施是使用随机数(不可猜测的一次性令牌),但为了抵御CSRF攻击,你仍须将其与预期的客户会话绑定在一起
-
5.5.4.1. 这个解决方案会为表单的CSRF令牌生成一个随机数,将令牌存储在一个由会话进行索引的表中,然后通过查找会话的随机数并判断它与表单中的随机数是否匹配,对表单进行验证
5.6. 现代浏览器在cookie上支持使用SameSite属性来缓解CSRF攻击
-
5.6.1. SameSite=Strict会阻止页面上的任何第三方请求向其他域发送cookie,这就会阻止CSRF攻击,但在导航到另一个需要其cookie的站点时可能会破坏由cookie带来的有用行为
-
5.6.2. 一种客户端侧对于CSRF的防御措施,服务器完全依赖它可能会面临风险,因此应该将其作为额外的缓解措施,而不是唯一的缓解措施
6. 注意的问题
6.1. 不要让攻击者将不受信任的输入注入HTTP头(类似于XSS)
6.2. 指定准确的MIME内容类型,以确保浏览器正确地处理响应
6.3. 开放式重定向可能会出现问题:不允许重定向到任意URL
6.4. 仅使用<IFRAME>嵌入你可以信任的网站(很多浏览器支持X-Frame-Options头缓解措施)
6.5. 在处理不受信任的XML数据时,要注意XXE攻击
6.6. CSS的:visited选择器可能会披露浏览器历史中是否有给定的URL
6.7. CSP(Content Security Policy,内容安全策略)响应头,以减少XSS暴露
-
6.7.1. 可以为脚本或图像指定拥有授权的来源(和其他类似功能),允许浏览器阻止从其他域注入内联脚本或其他恶意内容的尝试
-
6.7.2. 客户端侧的防御措施,不受你的控制,因此不要将其看作对XSS完全免疫的通行证
6.8. 在测试环境中,在所有Web页面中添加特定的安全策略,然后对网站进行测试,并针对每个问题追踪被阻止的行为
6.9. 很多HTTP响应头可以帮助你指定浏览器应该允许或不应该允许的内容,包括Content- Security-Policy响应头、Referrer-Policy响应头、Strict-Transport-Security响应头、X-Content-Type-Options响应头和X-Frame-Options响应头