---
# System prepended metadata

title: Week11 hw3：簡答題
tags: [2020十一月第三周, Lidemy心得, 進度筆記, BE101, PHP]

---

# 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>` ， 使留言板被劫持。  

![](https://i.imgur.com/Oiq5uKz.png)  

- 留言內容被解析成程式碼的一部分，既然可以寫 script 就可以做更多事情。  
- 離如導到其他網站，像是釣魚網站，或是用 `alert(document.cookie)` 去抓 SESSION ID 。 
- 這樣如果把目前觀看頁面的 user cookie ， 甚至傳到有心人的 server 。  
- 知道 user cookie 就可以得知 SESSION ID ， 再來就可以偷身分、資料，非常危險。 
- 所以應該做特殊處裡，把留言的一部分作成文字，而不是可以載入的 code 。   

### 修補 XSS 漏洞  
- ==`htmlspecialchars()` 可以把特殊字元編碼==，例如 `<` 是小於的符號，透過編碼後變成 `&lt;` 這字串就會被 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 產生。  

***