# Week11 hw3:簡答題
###### tags: `BE101` `PHP` `2020十一月第三周` `進度筆記` `Lidemy心得`
***
## ==1. 請說明雜湊跟加密的差別在哪裡,為什麼密碼要雜湊過後才存入資料庫:==
### 編碼(Encoding)
- 一開始的發展是編碼,把一團資料各自表述,使用不同方法來解釋,不用金鑰就能解碼的不安全方式。
### 加密(Encryption)
- 後來發展出加密,是一對一的方式。
- 用金鑰來保護重要資料的安全方法,且加密和解密過程都需要用到金鑰。
- 但其實沒那麼保險,如果被知道加密演算法,和金鑰,那被存在資料庫的密碼都會被解開。
```
明文(ex. aaa) → 加密 → 密文(ex. bbb)
密文(ex. bbb) → 解密 → 明文(ex. aaa)
```
### 雜湊(Hash)
- 因此發展出多對一的方式,會有很多種字串對應到有限的結果。
- 把一堆欄位的資料丟進某種 function (Hash function)進行運算,且得到的結果無法用來反推回原來的資料,也就是更難以取得使用者訊息。
```
明文(ex. aaa) → Hash → 文字(ex. j1o1h7n)
```
- 如果有兩不同東西產生同樣 Hash 的結果時被稱之為"碰撞"。
- 知名的演算法發生碰撞機率超級低,幾乎不太可能。
### 例如,取餘數
```
n%999
1 => hash =>1
2 => hash =>2
但 1001 => hash => 2
2000 => hash => 2
```
知道結果是 2 , 但是無法知道 hash 前輸入的值是多少,因此是單向的。
- sha256 > MD5(不安全) 。
- https://emn178.github.io/online-tools/sha256.html
- 使用者在註冊的時候,把其密碼經過 hash 後存到資料庫。
- 其 user 在登入時輸入的密碼一樣也透過 hash 後,與資料庫經 hash 的 user 密碼做比對,如果出來的結果一樣,代表輸入的值一樣,因此可以應用。
***
## ==2. include、require、include_once、require_once 的差別:==
### `include()` 函數
- 會將指定的文件訊息讀取後並執行裡面的code 。
### `require()` 函數
- 會將目標文件資料內容讀去後,並把自己本身換成這些讀取後的內容。
### `include_once()` 函數
- 在 code 執行時抓取並運行指定資料;此方法和 `include()` 語句類似,差別在於如果該文件中已經被抓取過,則不會再次抓取。而且只會抓取一次。
### `require_once()` 函數
- 和 `require()` 語句幾乎一樣,差別在於是由於 PHP 特性會檢查該資料是否已經被抓取過,如果有則不會再次被抓取。
***
## ==3. 請說明 SQL Injection 的攻擊原理以及防範方法:==
- User 登入網頁時,之前我們有透過 hash 的方式讓密碼被 hash 並存在 server 。
- 之前我們撈 username 的時候 , SQL 上的語法 `sql = sprintf("SELECT * from users where username='%s' and password='%s'", $username)` 是用字串拼接的方式。
- 而用 hash 的形式在 phpMyAdmin 上執行:
```
SELECT * from users where username='aa'#' and password='bbb'
相同於以下這段
SELECT * from users where username='aa'
```
'#' 之後的字都變黃色,代表註解;如果 username 用 '#' 字串傳入,這樣就會成立 query , 而且會以 aa 的身分登入網頁。
- 這樣會有個問題,知道 username 就可以任何人的身分登入。
### 不知道 user 身分也可以登入
```
SELECT * from users where username='%s' and password='%s'
如果改用這段
SELECT * from users where username='' or 1=1#
```
1=1 是 true , 會把資料庫所有的 users 都 select 出來。
- 也因此帳號填入 `' or 1=1#` , 而密碼隨便填:
```
username: ' or 1=1#
password:123
整段 query 變成
SELECT * from users where username='' or 1=1# and password='123'
```
這樣也會把所有資料都 select 出來。
- 也因此填入惡意構造的字串,注入到 SQL 後就會變成不同的意思,掌握了 query 。
### 新增留言的部分也能注入
```
INSERT INTO comments(nickname, content)
values('%s', '%s')
↓
nickname: a, content: b
↓
INSERT INTO comments(nickname, content)
values('a', 'b')
```
==INSERT INTO 的指令可以同時塞入多個指令。==
- 一個 INSERT INTO 可以塞入多筆資料。
- 這樣可以試著把原本的 query 改成,這樣塞入多筆資料的形式。
- 這樣就能控制 `content` 的 `%s` 例如:
```
content: '), ('admin', 'test')
↓
INSERT INTO comments(nickname, content)
values('%s', ''), ('admin', 'test')
```
Query 就會變成 insert into comments 然後塞入兩個 values 。
- 將這個 `'), ('admin', 'test')` 貼在沒有防止 SQL Injection 的留言板上會新增兩個 comments 。
- 應用字串拼接的方式來拼湊改造,達到想要的入侵目的。
### insert into 的內容可被修改
`insert into` 的內容可以是 `select` 的內容,例如:
```
insert into comments(nickname, content)
values('aaa', (select password from users limit1))
```
sub-query 的概念,一個 query 內可以有其他的 query 。
- 這樣就有被偷取密碼的風險,甚至可以更改、選定特定用戶的資料出來。
```
'), ((select username from users where id=40), (select password from users where id=40))#
```
這樣會把 `id=40` 的 user 的帳號和密碼給撈出來。
### 預設資料庫
- information schema : INNODB_SYS_TABLE 。
- 如果欄位的取名類似,可以被猜出來,用字串拼接(惡意字串)的方式下去撈出資料。
### 防範SQL injection方法
- Escape Parameters , 透過正規表達式對 user 輸入參數進行檢查,如有關鍵字符合 SQL 語法,則將它替換成合法字元。
```
缺點在於 SQL 的關鍵字一旦新增,檢查規則整個都要大改,因此總有漏洞,無法全面防範。
```
- Query Parameterization , 參數化查詢,大部分情況使用這防範方式相當安全,幾乎是安全解法;原理是資料庫語法中的佔位符號,丟進去的參數不會被執行。
```
SELECT * FROM person WHERE name = $1 AND password = $2
```
- White List (白名單),在特殊的情況下使用的,在 Query Parameterization 可能會失效的情況下用;常是使用 `Order By` 這樣可以根據條件選擇欄位排序,檢查並限制 user 的輸入欄位必須是固定數值。
```
SELECT * FROM users ORDER BY (CASE WHEN (TRUE) THEN lastname ELSE firstname)
```
***
## ==4. 請說明 XSS 的攻擊原理以及防範方法:==
### XSS (Cross-site Scripting)
- 跨網站執行 JS , 例如在留言板中滲入 `<script></script>` , 使留言板被劫持。

- 留言內容被解析成程式碼的一部分,既然可以寫 script 就可以做更多事情。
- 離如導到其他網站,像是釣魚網站,或是用 `alert(document.cookie)` 去抓 SESSION ID 。
- 這樣如果把目前觀看頁面的 user cookie , 甚至傳到有心人的 server 。
- 知道 user cookie 就可以得知 SESSION ID , 再來就可以偷身分、資料,非常危險。
- 所以應該做特殊處裡,把留言的一部分作成文字,而不是可以載入的 code 。
### 修補 XSS 漏洞
- ==`htmlspecialchars()` 可以把特殊字元編碼==,例如 `<` 是小於的符號,透過編碼後變成 `<` 這字串就會被 html 解釋成小於這個符號,而不是小於的 tag 。
- 把內容跳脫後再顯示出來,就可以讓 script 被當作"文字"。
```
<p class="card__content"><?php echo escape($row['content']); ?></p>
```
- 暱稱和建立時間也要跳脫,不然也會有 XSS 風險。
- 只要是使用者可以控制的地方都要注意到。
***
## ==5. 請說明 CSRF 的攻擊原理以及防範方法:==
- CSRF 是一種 Web 上的攻擊手法,全稱是 Cross Site Request Forgery,跨站請求偽造。
- 是點擊按鈕之後瀏覽器就會發送一個 GET 的請求給某個網址,如 `網址後接/delete?id=3` ,但因為瀏覽器的運行機制,會一併把該網址本身的 cookie 都帶上去。
- 而因 Server 端收到後檢查 session,發現是 user 的 request , 且這輸入訊息是 user 發的,於是就將訊息刪除。
### 防範方法
- user 每次瀏覽完後,登出所有輸入資料訊息,並且刪除 cookie 。
- Server 主動防禦,透過 request 的 header 內有欄位叫做 referer,代表這個 request 是從需求方要求並傳送,可檢查這欄位是不是合法的 domain,不是的話直接 reject 。
- 要注意,有些瀏覽器可能不帶 referer ; 有些 user 可能會關閉自動帶 referer 功能,這時 server 就會 reject 由真正 user 發出的 request ; 如果要檢查 domain 是否合法,則 code 必須要想辦法保證沒 bug 產生。
***