網站安全那些大小事
如果你正在學習使用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處理過
- $pwd = sha1(sha1($_POST['password']) + SALT);
- 延伸閱讀:我的密碼沒加密 - 什麼是「加密」?什麼是「沒加密」?
- 表單送出密碼時,先用javascript處理過
- input_pwd.value = sha1(sha1(input_pwd.value) + salt)
- 萬一你的user被監聽了,至少不會被拿到原始密碼
if (!DEBUG) error_reporting(0);
- error噴出來的資料可能會洩漏一些資訊
為了安全,不顯示錯誤
http://pastebin.com/z77Tx3ra
沒有留言:
張貼留言