# 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/ 並取得回應嗎?

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

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 攻擊情境。

```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. 根據上述設計的情境,說明開發者該如何預防。

```javascript=
button.addEventListener('click',()=>{
div.innerHTML = encodeURIComponent(input.value);
})
```
- 有可能被埋炸彈的地方,需各個擊破
1. HTML Content
2. HTML Attributes
3. URL
4. javaScript
5. CSS
6. 其他:Regex 、 JSON
>
>>[如何防禦 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 端添加。