2012
Nov
13

网页好读版


一个网站的最基本功能,通常会是会员系统,而会员系统也算是一项重要的功能,因为这里面包含的个人隐私与帐号、密码,一旦会员系统被骇客入侵,User 对网站的信任度也就会大幅下降,接著这篇文章将会介绍一些「登入程式逻辑」上的错误,造成系统的漏洞。

登入验证顺序错误

登入验证一定要在程式的最开端进行,而不能放在程式的中段,或是后段,曾经看过有工程师,将修改会员资料的逻辑处理,写在登入验证的前面。

updateMember.php 有问题的登入验证范例
  1. <?php
  2. updateMember($_POST['name']);
  3. if(!login()){
  4. echo '<script>alert("您尚未登入")</script>';
  5. exit(1);
  6. }
  7. ?>

上述的程式中,会先更新会员资料,然后再去验证会员是否有登入,而骇客只要将 data post updateMember.php , Php 程式就会先更新会员资料,接著弹出错误讯息给 User,因为顺序上的错误,造成骇客可以修改会员资料,甚至修改管理员的密码,而入侵整个网站。

登入验证失败后,未中断程式

当会员登入验证失败后,必需重导页面到登入画面,并且中断程式的运行,否则程式会继续执行,直到结束。

updateMember2-1.php 未中断程式运行范例
  1. <?php
  2. if(!login($account, $passwd)){
  3. echo '<script>confirm("你并非管理员,不可修改会员资料")</script>';
  4. }
  5. updateMember($_POST['name']);
  6. ?>

在范例 2-1 中,当验证登入失败后,会回传一段 javascript ,告知 user 并非登入中。

updateMember2-2.php 未中断程式运行范例
  1. <?php
  2. if(!login($account, $passwd)){
  3. header("location:login.php");
  4. }
  5. updateMember($_POST['name']);
  6. ?>

在范例 2-2 中,当验证登入失败后,会直接回传 http header ,告知 Browser重导到登入页。

这两个范例,虽然都有回传讯息给 user,告知无法修改会员资料,但是却漏掉 「exit(1)」中断程式的运行,骇客就可以不需要登入,而修改会员 or 管理员资料,入侵系统。

未对所有功能进行登入验证

「所有需要会员登入才能运作的功能,都要加上登入验证」,这句话看起没有大不了,大家也都知道,但是没有网路安全观念的工程师们,还是常常会写出漏掉验证的程式码。

index3-1.php 网站全部功能的入口页
  1. <?php
  2. if(!login($account, $passwd)){
  3. header("location:login.php");
  4. exit(1);
  5. }
  6. if($_POST['action'] == "updateMember") {
  7. require "updateMember3-2.php"; //更新会员资料
  8. }
  9. ?>
updateMember3-2.php 更新会员资料的 php file
  1. <?php
  2. updateMember($_POST['name']);
  3. ?>

有些工程师会将网站功能的入口都作在同一个 url 上,例如透过 index3-1.php 这一个页面,当传入的参数 action = updateMember ,就自动载入 updateMember3-2.php 并且完成会员更新的行为,因为 index3-1.php 这个档案的开头就已经先验证会员登入状态,所以工程师就会以为这个程式非常安全。

其实骇客只要直接将参数传给 updateMember3-2.php 这个 url ,跳过 index3-1.php ,就能轻易的再一次修改会员资料。

会员登入使用的 cookie 需加密

一般在会员登入之后,网站会建立一个代表这位会员已经登入过的 cookie 记录,有了这个记录,网站才知道这位会员不用再登入第二次,他可以执行会员应有的功能。

因为 cookie 是直接存在 Browser 里面,骇客可以轻易的看到 cookie 的格式是什么,所以我们还必需对 cookie 加密。

login4-1.php 会员登入页,错误的储存 cookie
  1. <?php
  2. if(login($_POST['account'], $_POST['password']){
  3. setcookie("member", base64_encode($_POST['account']));
  4. }
  5.  
  6. ?>

有不少工程师只会简单的对 cookie 做 base64 encode,这个加密出来的格式,很容易被骇客看出来,解密也相对简单,例如 「password」 base64 encode 过后的代码是 「cGFzc3dvcmQ=」,只要使用 base64_decode ,就能马上破解出来。

另外登入的 cookie 最好要加上后端程式能够判定的使用期限,再经过一段时间后,cookie 就不能再被使用,就算有骇客故意使用过期的 cookie,程式也要能过泸掉,为了这个功能,通常会在 cookie 的内容加入登入时间。

一个最基本的登入 cookie ,至少要会员密码,加上一个网站专用的固定 key,组合这二个数值,并且使用 md5 加密储存,而 key 也要三不五时的变换一下。

login4-2.php 一种正确的 cookie 加密方式
  1. <?php
  2. if(login($_POST['account'], $_POST['password']){
  3. $val = mcrypt_encrypt($cipher, $key, $_POST['account'].$expiredTime, $mode);
  4. $val .= md5($_POST['password'].$key);
  5. setcookie("member", $val);
  6. }
  7.  
  8. ?>
md5 只能算是最普通的加密方式,如果想要更好的安全机制,可以考虑其他的 Encrypt Library。

网页好读版