Like Share Discussion Bookmark Smile

J.J. Huang   2019-05-30   Web   瀏覽次數:

Web - 第二十一章 | HTML 發送表單資料

前面幾章節介紹的都屬於HTML的使用,這邊終於要深入探討到表單的資料再提交後,是提交到哪邊去。還記得當初我接觸程式這塊的時候,什麼都不懂,也是經歷過好一段日子才慢慢了解。現在網路上教學資源很多,都可以很有效幫助快速學習。

資料都去哪裡了?

客戶端/伺服器體系結構

web基於非常基本的客戶端/伺服器體系結構,可以總結如下:客戶端(通常是web瀏覽器)向伺服器發送請求(大多數情況下是ApacheNginxIISTomcat等web伺服器),使用HTTP協議。伺服器使用相同的協議來回答請求。

在客戶端,HTML表單只不過是一種方便的用戶友好的方式,可以配置HTTP請求將資料發送到伺服器。這使用戶能夠提供在HTTP請求中傳遞的訊息。

在客戶端:定義如何發送資料

<form>元素定義瞭如何發送資料。它的所有屬性都是為了讓你配置當用戶點擊提交按鈕時發送的請求。兩個最重要的屬性是action和method。

action 屬性

這個屬性定義了發送資料要去的位置。它的值必須是一個有效的URL。如果沒有提供此屬性,則資料將被發送到包含表單的頁面的URL。

送到絕對URL:

1
<form action="http://localhost:4000/">

送到相對URL:

1
<form action="/send">

在沒有屬性的情況下,資料被發送到表單出現的相同頁面上:

1
<form>

許多較老的頁面使用下面的符號表示資料應該被發送到包含表單的相同頁面;這是必需的,因為直到HTML5 action屬性都需要該符號。現在,這不再需要了。

1
<form action="#">

注:可以指定使用HTTPS(安全HTTP)協議的URL。當你這樣做時,資料將與請求的其餘部分一起加密,即使表單本身是託管在使用HTTP訪問的不安全頁面上。另一方面,如果表單是在安全頁面上託管的,但是你指定了一個不安全的HTTP URL,它帶有action屬性,所有的瀏覽器都會在每次嘗試發送資料時向用戶顯示一個安全警告,因為資料不會被加密。

method 屬性

HTTP協議提供了幾種執行請求的方法;HTML表單資料可以通過許多不同的資料傳輸,其中最常見的是GET方法和POST方法。

每當你想要訪問Web上的資源時,瀏覽器都會向URL發送一個請求。
HTTP請求由兩個部分組成:一個包含關於瀏覽器功能的全局元資料集的資料頭,一個包含伺服器處理特定請求所需訊息的主體。

GET 方法

GET方法是瀏覽器使用的方法,請求伺服器返回給定的資源:“嘿,伺服器,我想要得到這個資源。在這種情況下,瀏覽器發送一個空的主體。因為主體是空的,如果使用該方法發送一個表單,那麼發送到伺服器的資料將被追加到URL。

1
2
3
4
5
6
7
8
9
10
11
12
13
<form action="https://morosedog.gitlab.io/" method="get">
<div>
<label for="param1">參數一</label>
<input name="param1" id="param1" value="Hi">
</div>
<div>
<label for="param2">參數一</label>
<input name="param2" id="param2" value="J.J.">
</div>
<div>
<button>提交</button>
</div>
</form>

由於GET方法已經被使用,當你提交表單的時候,你將看到https://morosedog.gitlab.io/?param1=Hi&param2=J.J.在瀏覽器地址欄裡。

資料被附加到URL作為一系列的名稱/值對。在URL web地址結束之後,我們包括一個問號(?),後面是名稱/值對,每一個都由一個與符號(&)分隔開。

  • param1,它有一個Hi的值。
  • param2,它有一個J.J.的值。

HTTP請求如下:

POST 方法

POST方法略有不同。這是瀏覽器在請求響應時使用的一種方法,它需要考慮到HTTP請求體中提供的資料:“嘿,伺服器,看一下這些資料,然後給我回一個適當的結果。”如果使用該方法發送表單,則將資料追加到HTTP請求的主體中。

這邊僅僅把method改成post的方法即可

1
2
3
4
5
6
7
8
9
10
11
12
13
<form action="https://morosedog.gitlab.io/" method="post">
<div>
<label for="param1">參數一</label>
<input name="param1" id="param1" value="Hi">
</div>
<div>
<label for="param2">參數一</label>
<input name="param2" id="param2" value="J.J.">
</div>
<div>
<button>提交</button>
</div>
</form>

當使用POST方法提交表單時,你將沒有附加到URL的資料。

Content-Length資料頭表示主體的大小,Content-Type資料頭表示發送到伺服器的資源類型。


查看HTTP請求

HTTP請求永遠不會顯示給用戶(如果你想要看到它們,你需要使用諸如Firefox Network Monitor或Chrome Developer Tools之類的工具)。

唯一顯示給用戶的是被調用的URL。使用GET請求用戶將在他們的URL欄中看到資料,但是使用POST請求用戶將不會看到。

  • 如果你需要發送一個密碼(或其他敏感資料),永遠不要使用GET方法否則資料會在URL欄中顯示,這將非常不安全。
  • 如果你需要發送大量的資料,那麼POST方法是首選的,因為一些瀏覽器限制了URL的大小。此外,許多伺服器限制它們接受的URL的長度。

在伺服器端:檢索資料

可以參考Web - 第十七章 | HTML Form表單 - 向你的web伺服器發送表單資料 ,這邊是使用Java語言來做範例。

還有許多其他的伺服器端技術可以用於表單處理,包括Perl、Python、PHP、.Net、Ruby等。只挑你最喜歡的用就好。話雖如此,但值得注意的是,直接使用這些技術並不常見,因為這可能很棘手。更常見的是使用許多優秀的框架,這些框架使處理表單變得更容易。

  • 用於PHP的Symfony
  • 用於Python的Django
  • Node.js的Express
  • Ruby的Ruby On Rails
  • Java的Grails

要注意的是,即使使用這些框架,使用表單也不一定很容易。但這比從頭開始編寫所有功能要簡單得多,而且會節省很多時間。


特殊案例:發送文件

用HTML表單發送文件是一個特殊的例子。文件是二進制資料——或者被認為是這樣的——而所有其他資料都是文本資料。由於HTTP是一種文本協議,所以處理二進制資料有特殊的要求。

enctype 屬性

該屬性允許你指定在提交表單時所生成的請求中的Content-Type的HTTP資料頭的值。這個資料頭非常重要,因為它告訴伺服器正在發送什麼樣的資料。默認情況下,它的值是application/x-www-form-urlencoded。它的意思是:“這是已編碼為URL參數的表單資料。”

如果你想要發送文件,你需要額外的三個步驟:

  • 將method屬性設置為POST,因為文件內容不能放入URL參數中。
  • 將enctype的值設置為multipart/form-data,因為資料將被分成多個部分,每個文件分別對應一個文件以及表單正文中包含的文本資料(如果文本也輸入到表單中)。
  • 包含一個或多個File picker(文件選擇器)小部件,允許用戶選擇將要上傳的文件。
1
2
3
4
5
6
7
8
9
<form method="post" enctype="multipart/form-data">
<div>
<label for="file">選擇檔案</label>
<input type="file" id="file" name="myFile">
</div>
<div>
<button>上傳檔案</button>
</div>
</form>

注:一些瀏覽器支持<input>的multiple屬性,它允許選擇一個以上的文件上傳。但只使用一個<input>元素,伺服器如何處理這些文件取決於伺服器上使用的技術。

警告:為了防止濫用,許多伺服器配置了文件和HTTP請求的大小限制。在發送文件之前,先檢查伺服器管理員的權限是很重要的。


常見的安全問題

每次向伺服器發送資料時,都需要考慮安全性。到目前為止,HTML表單是最常見的攻擊媒介(可能發生攻擊的地方)。這些問題從來都不是來自HTML表單本身,它們來自於伺服器如何處理資料。

XSS和CSRF

跨站腳本(XSS)和跨站點請求偽造(CSRF)是常見的攻擊類型,它們發生在當你將用戶發送的資料顯示給用戶或另一個用戶時。

XSS允許攻擊者將客戶端腳本注入到其他用戶查看的Web頁面中。攻擊者可以使用跨站點腳本攻擊的漏洞來繞過諸如同源策略之類的訪問控制。這些攻擊的影響可能從一個小麻煩到一個重大的安全風險。

CSRF攻擊類似於XSS攻擊,因為它們以相同的方式攻擊——向Web頁面中註入客戶端腳本——但它們的目標是不同的。CSRF攻擊者試圖將特權升級到特權用戶(比如站點管理員)的權限,以執行他們不應該執行的操作(例如,將資料發送給一個不受信任的用戶)。

XSS攻擊利用用戶對web站點的信任,而CSRF攻擊則利用網站為其用戶提供的信任。

為了防止這些攻擊,你應該始終檢查用戶發送給伺服器的資料(如果需要顯示),盡量不要顯示用戶提供的HTML內容。相反,你應該處理用戶提供的資料,這樣你就不會逐字地顯示它。當今市場上幾乎所有的框架都實現了一個最小的過濾器,它可以從任何用戶發送的資料中刪除HTML <script>、<iframe>和<object>元素。這有助於降低風險,但並不一定會消除風險。

SQL注入

SQL注入是一種試圖在目標web站點使用的資料庫上執行操作的攻擊類型。這通常包括發送一個SQL請求,希望伺服器能夠執行它(通常,當應用伺服器試圖存儲由用戶發送的資料時)。這實際上是攻擊網站的主要途徑之一。

其後果可能是可怕的,從資料丟失到通過使用特權升級控制整個網站基礎設施的攻擊。這是一個非常嚴重的威脅,你永遠不應該存儲用戶發送的資料,而不執行一些清理工作。

HTTP資料頭注入和電子郵件注入

當你的應用程序基於表單上用戶的資料輸入構建HTTP頭部或電子郵件時,就會出現這種類型的攻擊。這些不會直接損害你的伺服器或影響你的用戶,但是它們是一個更深入的問題,例如會話劫持或網路釣魚攻擊。

這些攻擊大多是無聲的,並且可以將你的伺服器變成殭屍。

偏執:永遠不要相信你的用戶

最重要的原則是:永遠不要相信你的用戶,包括你自己;即使是一個值得信賴的用戶也可能被劫持。

所有到達伺服器的資料都必須經過檢查和消毒。總是這樣。沒有例外。

  • 有潛在危險的字符轉義。應該如何謹慎使用的特定字符取決於所使用的資料的上下文和所使用的伺服器平台,但是所有的伺服器端語言都有相應的功能。
  • 限制輸入的資料量,只允許有必要的資料。
  • 沙箱上傳文件(將它們存儲在不同的伺服器上,只允許通過不同的子域訪問文件,或者通過完全不同的域名訪問文件更好)。

如果你遵循這三條規則,你應該避免很多問題,但是如果你想要得到一個有能力的第三方執行的安全檢查,這是一個好主意。不要以為你已經看到了所有可能的問題。

這邊轉載了大量的文章和內容,但是每個部分我都有實際去做過,並了解過。這邊轉載主要是做筆記記錄。

註:以上參考了
MDN web docsSending form data 文章。
維基百科超文本傳輸協定 文章。