聊聊php安全之XSS和密码存储

跨站点脚本 (XSS)

跨站脚本或XSS是一种漏洞,它将客户端代码注入到web应用程序的输出中,并在用户的浏览器中执行。
成功后利用影响重定向到恶意网站 窃取凭据/cookie和CSRF令牌。
它是web应用程序中最常见的漏洞。

接下来是易受攻击的php代码示例。用户输入($_GET)正在输出未转义,这导致了最简单的反射XSS形式:

不安全的代码示例:

1
2
$search = $_GET['search'];
echo 'You have searched for: '.$search;

如果我们传递一个小的js代码而不是搜索词 <script>alert('xss');</script>,它会在页面呈现后立即执行:

php-security

有时我们会看到内嵌PHP和Javascript代码的混合,这些代码也可以轻松利用:

不安全的代码示例:

1
2
3
<script type="text/javascript"> 
var term = <?php echo $_GET['search']; ?>
</script>

在这个例子中,<script>标签是不需要的,因为参数直接被注入到js中。

跨站点脚本可以以多种方式利用。这意味着黑名单并不是一个好主意。推荐的方案是在输出之前转义数据。
当转义(编码)时,HTML字符被转换成HTML实体,这意味着浏览器不会将它们解释为代码而是数据。
php有两个函数可以用于转义数据,htmlspecialchars()htmlentities()

htmlspecialchars():此函数把预定义的字符转换为HTML实体。

  • &->&amp
  • "->&quot
  • '->&#039
  • <->&lt
  • >->&gt

htmlentities():这个函数非常相似,跟htmlspecialchars()唯一的区别是它编码所有具有HTML实体等价物的字符。

从PHP 5.6起,“UTF-8”是两个函数的默认字符集。

安全代码示例:

1
2
3
4
5
$search = $_GET['search'];
echo 'You have searched for: '.htmlspecialchars($search, ENT_QUOTES , 'UTF-8');

// Alternatively we can use the filter_var() function:
echo 'You have searched for: '.filter_var($search, FILTER_SANITIZE_FULL_SPECIAL_CHARS);

使用这两个函数,导致浏览器将“恶意”代码解析为文本:

php-security

在源代码中,我们可以看到阻止脚本执行的HTML编码字符:

php-security

密码存储

密码意味着私密,因为需要安全的存储它们 使web应用程序的一个非常重要的方面。
这增加了额外的安全层以避免在发生攻击时违法保密性。
如果攻击者利用web应该程序中sql注入漏洞并转存数据库,那么使用stronghash密码将会使它们的工作变成更加困难,从而避免进一步被黑。

密码存储中最重要的两个因素(除了强密码外) 是使用散列算法以及使用Salt。

Salt是在密码被散列之前添加到密码中的字符串。如果长且随机,那么他会使很多常见的破解方法(如字典攻击和查找表)失效。

不安全的代码示例:

1
2
3
$passwd = 'test123';
$hash = md5($passwd);
Result: cc03e747a6afbbcbf8be7668acfebee5

不能用md5()。你应该使用password_hash()功能。
该函数默认生成基于CRYPT_BLOWFISH算法(BCRYPT)的60个字符的字符串,并提供强大的哈希值。
此外,从php7.0开始,传递自定义Salt的选项已被弃用,首选使用默认生成的Salt.

该功能接受3个参数。散列密码,散列算法以及其他选项。在下面的例子中,我们将使用默认的哈希算法:

安全代码示例: hash创建

1
2
3
$passwd = 'test123';
$hash = password_hash($passwd,PASSWORD_DEFAULT);
Result: $2y$10$HYo4.XiLR5fe0tmRoIRM9.pJdAe68axSsDhScSAKgPDjLqsAEEGiO

哈希可以通过password_verify()函数进行验证。

安全代码示例: hash验证

1
2
3
4
5
$passwd = 'test123';
$hash = '$2y$10$HYo4.XiLR5fe0tmRoIRM9.pJdAe68axSsDhScSAKgPDjLqsAEEGiO';
if(password_verify($passwd,$hash)){
// Do action if the password is successfully verified
}

提示

  • 不要使用弱散列算法,如果MD5和SHA1
  • 不要使用(或重复使用)弱密码(让password_hash()生成强密码)
  • 不要创建你自己的加密或哈希函数
  • 不要存储加密密码,因为攻击者可能会访问私钥
  • 通过增加password_hash()函数中的cost值,可以获得更强大的哈希值(将值设的过高会影响服务器性能)
坚持原创技术分享,您的支持将鼓励我继续创作!