這篇會說明基本常見的駭客入侵與防禦的方法
- 有沒有印象使用瀏覽器的時候,莫名其妙被導到不知名網站,接著原本網站就莫名的被登出....?
- 或是忘記帳密時,收到一封有你帳密的 email,跟你說這是你忘記的帳密...?
諸如此類狀況,當下可能覺得還好,沒事,但事後回想,心裡還是會有點毛毛的....好像有種怪怪的感覺正在萌芽....
請說明雜湊跟加密的差別在哪裡,為什麼密碼要雜湊過後才存入資料庫
得先說明密碼為何不能存明碼。
雖然後端資料庫在儲存使用者的密碼時,不能存明碼已經是一種常識,儘管大家都覺得自家資料庫很安全,絕不可能攻破,但攻擊簡單防守難,攻擊者只要找到一個漏洞就可以鑽,防守者卻得思考所有可能的攻擊,防守範圍根本不一樣。
這時候就要預設最壞情況 -- 資料庫被駭了,駭客得到密碼了,不過好在不是存明碼的形式,駭客可能可以破解,但或許要花上十年、二十年,應該沒有多少駭客會願意,這樣我們或許就可以說我們防守成功。
接下來是一些超前部署部分,看看如何做到即使資料庫被駭了,使用者的真實密碼也不會洩漏出去
- 雜湊 (Hash)
不可逆。就算知道了雜湊過後的秘文,也無法回推出明文
- 將明文丟進公式後變成一串秘文
- 無論明文內容長短,透過雜湊演算法出來都是一樣的長度
- 同樣的輸入經過雜湊,保證一定會得到同樣的輸出
多對一關係,不同內容可能對應到同一組值,此情況稱為「碰撞(collision)」,但機率極低
補充:一個雜湊函式的好壞也取決於是否容易發生碰撞
由於無法逆向解出明文,安全性相較加密來的高
常見演算法:SHA 系列
方法:
- password_hash()
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
為 PHP 內建的 hash() 函式,只需要將加密方式傳給 hash() 函式。可以直接指明 sha256, sha512, md5, sha1 等加密方式
ex:$password = hash("sha256", $password);
將經過演算法的密碼儲存在變數中
- 第一個參數是原始 password,第二個參數是演算法,建議可使用
PASSWORD_DEFAULT
,每次處理都會產生隨機的 SALT
password_verify()
$password = 'ilovecoding12345' // 原始密碼 if(password_verify($password, $row_['password])) { $_SESSION['name'] = $username; } else { header('Location: login.php?errCode=2'); die(); } header('Location: index.php');
- 檢查輸入的密碼是否存在相對應的資料,是則導回首頁,否則導回登入頁並報錯
- 將經過
password_hash()
處理的密碼,進行驗證,用於登入功能 password_verify('使用者輸入的密碼', '資料庫裡的密碼')
,根據回傳的 boolean 值,進行操作
加密 (Encryption)
可逆。知道了加密後的秘文,只要知道金鑰,就可以還原出明文- 將明文資訊改變成難以讀取的密文,例如常見的「凱薩加密」,可透過「解密」還原內容
- 加密與解密都同樣要透過金鑰來執行
- 一對一對應關係
分為對稱與非對稱式
對稱式加密:
- AES, DES 等
- 發送者與持有者持有相同金鑰來加解密資訊
- 傳遞金鑰的過程中(發送 request, response)被竊取資訊的話,再強的加密演算法都沒有用,因此有了非對稱式加密
- 明文 ABC,經由加密後每位向後移三位,變成 CDE,這樣就是簡單的對稱式加密
非對稱式:
- RSA, DSA 等
- 使用者都擁有一對金鑰,公鑰加密,私鑰解密
- 訊息由其中一把公鑰加密,必須由另一把私鑰解密
- 安全性相較對稱式來得更高
- 有五人 ABCD 與 E,還有一口箱子,E 將唯一一把私鑰留給自己,公鑰分別發給其餘四人一人一把,並且說:「有人想跟他說悄悄話就把訊息放到箱子裡上鎖」,過幾天 E 打開箱子真的有訊息。
藉由上述,我們知道只有 E 能開箱子,因為只有他有唯一一把私鑰,同時確保只有 E 能看到其中的內容
額外補充 -- 雜湊加鹽(SALT)
一樣的密碼經過雜湊以後,就一定會有一樣的雜湊值,針對這一點,建立一個常用字串對照雜湊值的表格,藉此強硬破解雜湊後的密碼
我們叫它「彩虹表」
至於如何防範?我們只要給密碼加鹽(SALT)就可以。
在原本密碼雜湊前,先加入一段固定字串(SALT),比如在原本密碼前我們都先加上 1234
ilovecoding1234(SALT) -> 1234ilovecoding1234
這樣即使有了對照表,也不知道加入了什麼鹽或是怎麼加的,短時間也難以破解。
本人輸入密碼的話,只要照著原本方式加鹽回去,做雜湊,比較是否吻合資料庫中的雜湊值就可以了。
雜湊常用在平台上的密碼驗證,因為平台實際上不需要知道使用者真正輸入的密碼,透過雜湊不可逆的機制,可以最好的保護使用者的明碼。而區塊鏈則會用到不對稱式加密的機制,讓一個訊息能透過私鑰及公鑰被加密傳輸與保護。而編碼基本上毫無安全性可言,換個方式表達而已,像是摩斯密碼,只要有人懂這套規則就能輕易轉譯回來。
簡單說,密碼存明碼就是違反資訊安全的起手式!!不可姑息!!
include
、require
、include_once
、require_once
的差別
此四種函式的作用都是包含並執行指定檔案,最主要差別在使用時機
include()和 require()差別
- include() 引入檔案時,如遇到錯誤,會提示錯誤並繼續執行。
- require() 引入檔案時,如遇到錯誤,會提示錯誤並終止執行。
- require() 通常放在 php 頁面最前,php 在執行前就會先讀入 require()引入的檔案,檔案內容會變成此頁指令碼的一部份,include()只在用到時才放進來,通常是放在流程控制的處理區段中,php 指令碼在執行到它時,才會將檔案包含進來。即 require()是預載入機制,位置在指令碼最前面,一開始就引入所有可能用到的檔案;include()是即用即載入,位置靈活。
在後面加上
_once
的區別- include()、require()執行即包含檔案,不會對引入的檔案進行比較判斷,可能會出現重複包含的情況;而 include_once()、require_once()在包含時會先判斷檔案是否已經包含過了,如果已包含,則不再包含檔案,這樣的引入檔案方式即可以節省資源,又可避免重複定義的錯誤。
請說明 SQL Injection 的攻擊原理以及防範方法
SQL 語法常用於 database 系統中,攻擊者可透過更改語法邏輯或加入惡意特殊指令方式,竊取或修改資料
防禦方法:prepared statement
「參數化查詢」或是「預處理」,簡單說就是另外準備好參數來給值,在所有需要填入數值或資料的地方。Prepared Statement 會替 SQL 語句進行預處理,利用提供的 bindValue 或 bindParam 函式將欲查詢的參數或數值綁定上去,底層查詢時,其參數會保證作為數值傳遞,不會成為 SQL 語句的一部份,因此可避免掉 SQL Injection 的問題
方法舉例
<?ph $sql = 'INSERT INTO comments (username, content) VALUE (?, ?)'; // 準備好 SQL 語法,用問號(稱為佔位符或參數)替換查詢中的所有變量 $stmt = $connect->prepare($sql); // 準備結果查詢 $stmt->bind_param('ss', $username, $content); //將所有變量綁定到先前準備的語句 $result = $stmt->execute(); // 執行語句 ?>
建議所有要下 sql 的地方都要加上預處理方法(prepared statement)
請說明 XSS 的攻擊原理以及防範方法
Cross-site scripting,跨網站指令碼攻擊。
- 透過網頁開發時的漏洞,在使用者可以輸入訊息的地方,輸入惡意指令碼,透過被攻擊者的身份去執行一些管理的動作以得到想要的資訊(帳號、密碼等),或是導向到釣魚網站。
惡意指令碼通常是 JavaScript,但其他語言 HTML, CSS, JAVA 等也都有可能
防禦方法
htmlspecialchars()將預定義的特殊字元轉換成 HTML 僅能顯示用的編碼
語法
htmlspecialchars( $string , $quote_flags , $encoding , $double_encode )
- $string: 須轉換的字串
- $quote_flags: 用來設定引號的轉換,基本上建議使用 ENT_QUOTES 單雙引號都轉換(預設是僅轉換雙引號)
- $encoding: 用來設定要轉換的編碼,預設是 UTF-8
- $double_encode: 是否要對全部進行轉換,預設值是轉換全部的 HTML 碼
請說明 CSRF 的攻擊原理以及防範方法
Cross Site Request Forgery,跨站請求偽造
- 當用戶登錄網站時,聯覽器會記錄 cookies,如果用戶未登出或 cookies 未過期(關閉瀏覽器並不代表網站已登出或 cookies 可立即過期)的期間,造訪了其他危險或不知名網站,點擊了攻擊者的連結,便會向原網站發出某項功能請求(request),原網站的伺服器接收後會誤以為是用戶合法操作而執行。
簡單舉例,可能是在某大型平台點擊了某項連結,進而被導到其他(釣魚)網站,點了不知名的按鈕,然後就被駭客利用你本人發送 request 去取得某平台的資料或做出某項行為。
防範手法
用戶端
- 使用完記得登出,也別隨意瀏覽不明網站
- 避免在瀏覽器自動儲存帳密
- 基本上,用戶端能做的不多
伺服器端
- request 裡面有一個欄位叫做 referer,代表這個 request 從哪裡來,可以檢查這個欄位是不是合法 domain
- 加上圖形或簡訊驗證碼,常見於銀行帳戶等需要高度安全的領域,若每個網頁都這樣,也實在不方便
- 加上 CSRF token,在 form 裡面加上一個 hidden 欄位,叫做 CSRF token,其中填入由 server 隨機產生的一組亂碼並且存在 server 的 session 中,提交後,server 比對 form 中的 token 是否跟 session 中的一樣,來確認是不是本人發出的 request,每一段不同 session 就應該要更換一次 CSRF token,但是攻擊者若是掌握任一個你底下的 subdomain,就可以幫你寫 cookie 且順利攻擊
- Double Submit Cookie,解法與第 CSRF token 類似,前半段同樣都由 server 產生一組隨機的 token 且加在 form 上面,不同點在後面,不用把這個值寫在 session 保存在 server 外,同時讓 client side 設定一個叫 CSRF token 的 cookie,值也是一組 cookie,利用cookie 只會從相同 domain 帶上來的機制,使攻擊者無法從不同 domain 得到此 cookie
瀏覽器端
SameSite cookie,簡單說只要 cookie 不是從原網頁來的就會被消除掉,但目前只有 chrome 支持
原先:Set-Cookie: session_id=ewfewjf23o1;
- 修正:Set-Cookie: session_id=ewfewjf23o1; SameSite
上述有幾點攻擊手法都是類似的,總歸一句:
「 永遠不要相信來自 client 的資訊 」
就可以避免掉很多惡意攻擊