---
# System prepended metadata

title: Week 8 回顧

---

# Week 8 回顧

## 主題⼀：使⽤ Grid 完成排版
1. 說明 Grid 的基本設定觀念。
    - 一組水平線（row）和垂直線（column）的交叉集合（intersecting set）。
    - 相較於一維的 flex，grid 是二維的網格系統，可以指定內元件排版在網格的任何地方。
    - 可以使用 px 指定絕對大小、 % 設定百分比或 fr 代表剩餘空間欲分配的比例。

2. 利⽤ Grid 完成第⼀週作業，下⽅主內容 ( 景點列表 ) 的前端排版。
```html= 
<section>
    <div class="grid-box">
        <div class="box-bottom">
            <img src="./imgs/1.jpg" alt="">
            <i class="fa fa-star" aria-hidden="true"></i>
            <figcaption>Title</figcaption>
        </div>
    </div>
</section>
```
```css=
section{
    display: flex; /*flex與grid不衝突*/
    justify-content:center;
}
.grid-box{
    display: grid;
    grid-template-columns: repeat(4, 1fr); /*網格區塊的寬度大小*/
    grid-column-gap: 20px; /*網格區塊的左右間距*/
    grid-row-gap: 20px; /*網格區塊的上下間距*/
}
.box-bottom{
    display: inline-grid; /*inline讓元素可以拼在一起*/
}
.box-bottom img{
    grid-area: 1 / 1 / 2 / 2; 
    /*row-start/column-start/row-end/column-end*/
}
```

## 主題⼆：完善資料驗證程序
1. 前端在使⽤者註冊、登入時，要先驗證資料是否忘記輸入，格式是否正確，並在錯誤時，直接提醒使⽤者。沒有任何錯誤，才發送請求到後端。
>https://www.javascripttutorial.net/javascript-dom/javascript-form/
```html=
<form action="/signup" method="POST" id="signup">
    <div>
        <label for="password">密碼</label>
        <input type="password" 
            id="password"
            name="password"
            onfocusout="addTip('password','密碼')"
            // 離開 input 時偵測，若為空白則出現提示
            onkeyup="removeTip('password')"
            // 輸入文字進 input 時將提示移除
            pattern="^[^ ].+[^ ]$">
/*  正則表達式
    第一個 ^ 代表「字串的起始」；
    [^ ] 代表「除了空白以外的所有字符」；
    .+ 代表「最少一個字符」；
    最後的 $ 代表「字串的結束」。
*/
    </div>
    <div id="error-password" class="errorText"></div>
</form>
```
```javascript=
let signUpForm = document.getElementById("signup");
signUpForm.addEventListener("submit", function (event) {
    //暫停傳送表單
	event.preventDefault();
    //確認每個欄位是否有效
    let nameValid = hasValue(signUpForm, 'name', '姓名');
	let usernameValid = hasValue(signUpForm, 'username', '帳號');
    let passwordValid = hasValue(signUpForm, 'password', '密碼');
    //都有效時傳送表單
	if (nameValid && usernameValid && passwordValid) {
		signUpForm.submit()
	}
});


function hasValue(form, inputId, text) {
	if (form.elements[inputId].value.trim() === "") {
		return addTip(inputId, text);
	}
	return true;
}

function addTip(inputId,text){
    let inputBox = document.getElementById(inputId);
    if(inputBox.value == ''){
        inputBox.className = "error";
        let errorDiv = document.getElementById("error-"+inputId);
        errorDiv.textContent = "請輸入"+text;
    }
}

function removeTip(inputId){
    let inputBox = document.getElementById(inputId);
    if(inputBox.value != ''){
        inputBox.classList.remove("error");
        let errorDiv = document.getElementById("error-"+inputId);
        errorDiv.textContent = "";
    }
}
```
```css= 
.error{
    border: 2px solid red;
}
```
2. 後端接收到前端的請求時，要驗證資料是否存在，且資料格式是否符合預期，⼀切都正確才能執⾏後續的資料庫操作。否則就直接回應錯誤訊息給前端。
```python= 
name = req.form["name"]
username = req.form["username"]
password = req.form["password"]
sql = "SELECT * FROM member WHERE username = %s"
val = (username)
mycursor.execute(sql,(val,))
myresult = mycursor.fetchone()
if not myresult == None:
    return redirect("/error?message=帳號已經被註冊")

pass
```
3. 請在你的註冊、登入會員的功能中，建立以上資料驗證程序並展⽰出來。
>https://github.com/Pinkowo/WeHelp/tree/main/wk8

4. 在我們的系統中，前端驗證和後端驗證的主要⽤途是什麼？
    - 前端驗證：向**使用者**確認每個欄位有被輸入以及格式皆正確。
    - 後端驗證：向**前端**確認資料格式是否正確，以及向**資料庫**確認是否有該筆資料。

## 主題三：AJAX 與 CORS
1. 什麼是 CORS？
    - 跨來源資源共用 ( Cross-Origin Resource Sharing )。
    - 使用額外 HTTP 標頭令目前瀏覽網站的使用者代理 (en-US)取得存取其他來源（網域）伺服器特定資源權限的機制。
    - 基於安全性考量，程式碼所發出的跨來源 HTTP 請求會受到限制。例如：XMLHttpRequest 及 Fetch 都遵守同源政策（same-origin policy，相同的通訊協定/網域/通訊埠）。這代表網路應用程式所使用的 API 除非使用 CORS 標頭，否則只能請求與應用程式相同網域的 HTTP 資源。

2. 我們可以在⾃⼰的網⾴中，使⽤ fetch() 或是 XMLHttpRequest 連結到 https://www.google.com/ 並取得回應嗎？
![](https://i.imgur.com/MCaaqeJ.png)

3. 我們可以在⾃⼰的網⾴中，使⽤ fetch() 或是 XMLHttpRequest 連結到 https://padax.github.io/taipei-day-trip-resources/taipei-attractions-assignment.json 並取得回應嗎？和上述的狀況，差別在哪裡？
![](https://i.imgur.com/JSxnXir.png)

4. 如何開放我們⾃⼰開發的 API，讓別的網站透過 fecth() 或是 XMLHttpRequest 連結，達到如同第 3 點的可能性。
    - 授權的方法是在 response 裡加上 Access-Control-Allow-Origin header：
    >Access-Control-Allow-Origin: https://shubo.io
    - 如果 server 允許任何來源的跨來源請求，那可以直接回 *：
    >Access-Control-Allow-Origin: *
## 主題四：使⽤主鍵、索引優化資料庫查詢效率
1. 了解主鍵 (Primary Key) 和索引 (Index) 的觀念。
    - 主鍵
        - 具有唯一性且不可為 null。
        - 可避免產生一堆重複又無法識別的 row。
        - 方便撈到指定的 row。
        - 外鍵參照（foreign key reference）。
    - 索引：
        - 索引越多，需要的記憶體與維護索引的 cpu 運算也越多。
        - 
2. 請在 member 資料表中加入適當的索引，加快以下 SQL 語句的查詢效率：SELECT * FROM member WHERE username=’test’ and password=’test’
3. 如何驗證查詢效率是否真的變更好了？
4. 為什麼索引的設置能有效地改善查詢效率？
## 主題五：使⽤ Connection Pool 連結資料庫
1. 什麼是 Connection Pool？能帶給我們什麼好處？為什麼？
    1. mySQL的伺服器擴充套件。
    2. 減少開關、統一出口、設定最大連線數、驗證 connection 是否正常。
    3. 不使用 connection pool 的話，每當要查詢、新增、刪除等動作，都必須**重複打開資料庫後關閉**，每次連接都很耗時跟耗資源，而 **connection pool 可以保持數據庫持續連結**，以便有請求時就可以馬上使用，不必重新創建連結。
2. 如何使⽤官⽅提供的 mysql-connector-python 套件，建立 Connection Pool。
3. 需要從資料庫取得查詢資料時，如何從 Connection Pool 取得 Connection，並且在資料操作結束後，歸還 Connection 到 Connetion Pool 中。請展⽰你完成上述標準操作的程式碼。
> SHOW PROCESSLIST
## 主題六：了解並預防 Cross-Site Scripting (XSS) 攻擊
1. XSS 攻擊的基本介紹。
    - 當網站讀取時，執行攻擊者提供的程式碼。
    - XSS 攻擊分為兩種
        1. Reflected Attack：使用者點擊連結。
        2. Persistent Attack：單純瀏覽網頁，但該網頁中已植入惡意的語法。
2. 實際設計⼀個 XSS 攻擊情境。
![](https://i.imgur.com/2e9sdei.png)
```html=
<input type="text" id="input">
<button id="button">click me</button>
<div id="div"></div>
```
```javascript= 
let input = document.getElementById("input");
let button = document.getElementById("button");
let div = document.getElementById("div");

button.addEventListener('click',()=>{
    div.innerHTML = input.value;
})
```
3. 根據上述設計的情境，說明開發者該如何預防。
![](https://i.imgur.com/XFLAgKL.png)
```javascript= 
button.addEventListener('click',()=>{
    div.innerHTML = encodeURIComponent(input.value);
})
```
- 有可能被埋炸彈的地方，需各個擊破
    1. HTML Content
    2. HTML Attributes
    3. URL
    4. javaScript
    5. CSS
    6. 其他：Regex 、 JSON
>![](https://i.imgur.com/Tz56j9A.png)
>>[如何防禦 XSS 攻擊](https://medium.com/hannah-lin/xss-2-%E5%A6%82%E4%BD%95%E9%98%B2%E7%A6%A6-xss-%E6%94%BB%E6%93%8A-18fdf10ef5ef)
#### 1. HTML Content
先透過編碼後再進行輸出。
在 Javascript 中使用 **encodeURI()** 和 **encodeURIComponent()**（escape() 已經沒在使用了）。
```javascript=
var set1 = ";,/?:@&=+$";  // 保留字符
var set2 = "-_.!~*'()";   // 不转义字符
var set3 = "#";           // 数字标志
var set4 = "ABC abc 123"; // 字母数字字符和空格

console.log(encodeURI(set1)); // ;,/?:@&=+$
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURI(set3)); // #
console.log(encodeURI(set4)); // ABC%20abc%20123 (空格被编码为 %20)

console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24
console.log(encodeURIComponent(set2)); // -_.!~*'()
console.log(encodeURIComponent(set3)); // %23
console.log(encodeURIComponent(set4)); // ABC%20abc%20123 (空格被编码为 %20)
```

#### 2. HTML Attributes
同上。
#### 3. URL
只推薦用 **encodeURIComponent()** ，因其包含 & ? + = 等字符的轉碼。
#### 4. javaScript
在特殊字符（" ' \` $ / \）的前面加上 \ 將其變為一般字元。
```javascript= 
function addslashes( str ) {
    return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
}
```
#### 5. CSS 
同上，通常 style/script 已經分離，因此相對安全，只需針對 \ 及 / 做重新編碼。

### CSP
當今天已被安裝炸彈，設定 CSP (白名單) 可以防止炸彈爆炸。建議於 sever 端添加。

