2013/12/01

如何寫出安全的PHP網站

網站安全那些大小事

如果你正在學習使用PHP(其實任何語言都通用)開發網站...
請務必要注意到安全性的問題
特別是有開放留言、註冊功能之類的網站!

有留言板,就有人想 <script> ...
有登入系統,就有人想 'or''=' ...

可以寫<script>的留言板,黑客就可以偷走你的cookie
甚至偷走你的密碼,進入後台搞破壞
萬一你的密碼是萬用密碼,拿到之後每個網站都可以登入
那你就損失慘重了!

至於可以寫單引號的系統呢?
如果你寫了...

$query = mysql_query("DELETE FROM `messages` WHERE " .
                     "`mid` = '{$_POST['id']}' AND " .
                     "`del_code` = '{$_POST['code']}'");

像這樣具有刪除留言功能的留言板
那麼我只要搞破壞,在code欄位輸入了 ' or '' = ' ...
整個 SQL 命令就會變成

DELETE FROM `messages` WHERE `mid` = '' AND `del_code` = '' or '' = ''

看清楚了嗎?

or '' = ''

然後你整張資料表的內容就...
萬一這是使用者刪除帳號的功能呢?

只要把握一個原則,就可以寫出很安全的網頁




Never Trust User Input, Forever.

 就算是在後台也一樣
不管是前台還是後台,都要要檢查使用者輸入資料格式、範圍是否正確
並且正確的 escape 掉所有的 SQL 和 HTML
如此一來,你的網站安全就能夠大大的提升了

好了,我已經講完了

「等等,這不是有講跟沒講一樣嗎?」

摁,所以來講些實作上的東西

Never Trust User Input Data

  • 取得使用者IP?
    • HTTP_X_FORWARDED_FOR
    • HTTP_CLIENT_IP
    • REMOTE_ADDR
    • 請全部記下來...
  • 如果我要限制使用者IP呢?
    • REMOTE_ADDR
    • 其他的通通都能輕易偽造

登入系統絕對不能只靠cookie判斷

  • if ($_COOKIE['user_login'] == "admin") { echo "歡迎回來,管理員大大"; }
  • javascript: document.cookie = "user_login=admin"; // Hi, I'm cracker.
  • SESSION是你的好夥伴
  • SESSION ID請使用http-only的cookie來存,確保JS讀不到
  • SESSION內存放登入有效期限,超過就強制登出

 組合 SQL 前,檢查並且escape所有放進去的參數

  • mysqli_real_escape_string // mysql_* 要廢棄了,全面改用mysqli
  • mysqli::prepare
  • PDO
  • ORM framework
  • IP位址也要escape...
    • HTTP_X_FORWARDED_FOR 也能注
  • 如果你要把資料從DB query出來,再存進去,記得也要再次escape
    • 延伸閱讀:2nd sql injection
  • 絕對要使用正確的方式做escape
    • 絕對不要認為 htmlentities 可以保護你的資料庫
      • But... XSS還是要靠他

輸出前記得要escape html擋XSS

  • htmlentities
    • 使用 ENT_IGNORE時請小心
      • 可以利用文字編碼繞過 escape
  •  統一入資料庫前或者輸出前escape一次就好
    • 我遇過被escape兩次的
      ...
      幹....

CAPTCHA 的內容絕對不要放 cookie 或者img的alt...

  • <img src="captcha.php?code=dr5gh" alt="請輸入:dr5gh" id="img_captcha" />
    • var captcha = document.querySelector("#captcha").alt.substr(4);
  • 乖乖用SESSION啦

重要的操作請勿使用GET方法

  • <img src="http://your.website.com/user/delete_my_account.php?confirm=yes" />
  • 你看你又悲劇了
  • POST + one time token + check referer
    • <input type="hidden" name="token" value="blablablabla_store_in_session" />

避免不安全的使用eval()

Server儲存密碼的時候請使用hash處理過

if (!DEBUG) error_reporting(0);

  •  error噴出來的資料可能會洩漏一些資訊
    為了安全,不顯示錯誤
就先寫到這裡吧,最後來個留言板Demo...
http://pastebin.com/z77Tx3ra

沒有留言:

張貼留言