【H5】15 表单 其四 数据发送

一旦在客户端上验证了表单数据,就可以提交表单了。

并且,由于我们在上一篇文章中介绍了验证,因此我们准备提交!

本文着眼于用户提交表单时会发生什么—数据将流向何处,以及到达表单后如何处理?

我们还将研究与发送表单数据相关的一些安全问题。

先决条件: 基本的计算机知识,对HTML理解以及HTTP服务器端编程的基本知识
目的: 了解提交表单数据时会发生什么,包括了解如何在服务器上处理数据的基本概念

首先,我们将讨论提交表单时数据发生什么情况。


 

客户端/服务器架构

从根本上讲,Web使用客户端/服务器体系结构,可以将其总结如下。

客户端(通常是Web浏览器)使用HTTP协议将请求发送到服务器(大多数情况下是Web服务器,例如ApacheNginxIISTomcat等)

服务器使用相同的协议回答请求。

Web客户端/服务器体系结构的基本架构

网页上的HTML表单无非是一种方便的用户友好方式,用于配置HTTP请求以将数据发送到服务器。

这使用户能够提供要在HTTP请求中传递的信息。

注意:要更好地了解客户端-服务器体系结构如何工作,请阅读我们的服务器端网站编程第一步模块。


 

在客户端:定义如何发送数据

<form>元素定义了数据如何发送。

所有属性旨在让您配置当用户单击“提交”按钮时要发送的请求。

两个最重要的属性是actionmethod


 

动作属性

action属性定义将数据发送到的位置。其值必须是有效的相对URL或绝对URL

如果未提供此属性,则数据将发送到包含表单的页面的URL —当前页面。

在此示例中,数据被发送到绝对URL — https://example.com

<form action="https://example.com">

在这里,我们使用相对URL —数据被发送到同一来源的不同URL:

<form action="/somewhere_else">

 

如果不指定任何属性,则如下所示,<form>数据将发送到表单所在的同一页面:

<form>

 

注意:可以指定使用HTTPS(安全HTTP)协议的URL。

执行此操作时,即使表单本身托管在使用HTTP访问的不安全页面上,数据也会与请求的其余部分一起被加密。

另一方面,如果表单托管在安全页面上,但是您使用action属性指定了不安全的HTTP URL,则所有浏览器每次尝试发送数据时都会向用户显示安全警告,因为数据不会被加密。

非文件格式控件的名称和值以name=value与“&”符号成对的形式发送到服务器

action值应该是服务器上可以处理传入数据(包括确保服务器端验证)的文件。

然后,服务器会做出响应,通常会处理数据并加载由action属性定义的URL ,从而导致新页面加载(如果action指向同一页面,则刷新现有页面)。

数据的发送方式取决于method属性。


 

方法属性

method属性定义如何发送数据。

HTTP协议提供了几种方法来执行的请求; 

HTML表单数据可以通过许多不同的方法来发送时,最常见的是GET方法和POST方法

要了解这两种方法之间的区别,让我们退一步并检查HTTP的工作原理

每次您想访问Web资源时,浏览器都会向URL发送请求。

HTTP请求由两部分组成:标头,包含与浏览器功能有关的一组全局元数据;

以及正文,可以包含服务器处理特定请求所需的信息。

GET方法

GET方法是浏览器用来请求服务器发回给定资源的方法:“嘿,服务器,我想获取此资源。”

在这种情况下,浏览器将发送一个空的正文。

因为主体为空,所以如果使用此方法发送表单,则发送到服务器的数据将附加到URL。

考虑以下形式:

<form action="http://www.foo.com" method="GET">
  <div>
    <label for="say">What greeting do you want to say?</label>
    <input name="say" id="say" value="Hi">
  </div>
  <div>
    <label for="to">Who do you want to say it to?</label>
    <input name="to" id="to" value="Mom">
  </div>
  <div>
    <button>Send my greetings</button>
  </div>
</form>

 

由于使用了该GET方法,因此您www.foo.com/?say=Hi&to=Mom在提交表单时会在浏览器地址栏中看到该URL 

数据作为一系列名称/值对附加到URL。

URL网址结束后,我们在问号(?)后面加上名称/值对,每对之间用&符号(&分隔

在这种情况下,我们将向服务器传递两个数据:

  • say,其值为 Hi
  • to,其值为 Mom

HTTP请求如下所示:

GET /?say=Hi&to=Mom HTTP/2.0
Host: foo.com

注意:您可以在GitHub上找到此示例—请参阅get-method.html另请参见在线示例)。


 

POST方法

POST方法是有点不同。这是浏览器在请求响应时使用的一种方法,该响应考虑了HTTP请求正文中提供的数据:“服务器,请看一下这些数据,然后将适当的结果发送给我。”

 如果使用此方法发送表单,则数据将附加到HTTP请求的正文中。

让我们看一个例子—这与我们在上一GET节中看到的形式相同,但是method属性设置为POST

<form action="https://www.foo.com" method="POST">
  <div>
    <label for="say">What greeting do you want to say?</label>
    <input name="say" id="say" value="Hi">
  </div>
  <div>
    <label for="to">Who do you want to say it to?</label>
    <input name="to" id="to" value="Mom">
  </div>
  <div>
    <button>Send my greetings</button>
  </div>
</form>

 

使用该POST方法提交表单时,没有任何数据附加到URL,HTTP请求看起来像这样,数据包含在请求正文中:

POST / HTTP/2.0
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

say=Hi&to=Mom

Content-Length报头指示所述主体的尺寸,并且Content-Type报头指示发送给服务器的资源的类型。

稍后我们将讨论这些标题。

注意:您可以在GitHub上找到此示例—请参阅post-method.html另请参见在线示例)。

查看HTTP请求

HTTP请求永远不会显示给用户(如果要查看它们,则需要使用Firefox Network MonitorChrome Developer Tools之类的工具)。

例如,您的表单数据将在Chrome的“网络”标签中显示如下。提交表格后:

  1. 打开开发人员工具。
  2. 选择“网络”
  3. 全选”
  4. 在“名称”标签中选择“ foo.com”
  5. 选择“标题”

然后,您可以获取表单数据,如下图所示。

向用户显示的唯一内容是称为URL。

如上所述,通过GET请求,用户将在其URL栏中看到数据,但通过请求,用户将不会看到POST

这可能非常重要,原因有两个:

  1. 如果您需要发送密码(或任何其他敏感数据),请不要使用该GET方法,否则您可能会在URL栏中显示该密码,这是非常不安全的。
  2. 如果需要发送大量数据,POST则首选方法,因为某些浏览器会限制URL的大小。另外,许多服务器限制了它们接受的URL的长度。

 

在服务器端:检索数据

无论选择哪种HTTP方法,服务器都会接收一个字符串,该字符串将被解析以便以键/值对列表的形式获取数据。

访问此列表的方式取决于您使用的开发平台以及与之配合使用的任何特定框架。

示例:原始PHP

PHP提供了一些全局对象来访问数据。假设您已经使用了该POST方法,下面的示例仅获取数据并将其显示给用户。当然,如何处理数据取决于您自己。您可能会显示它,将其存储到数据库中,通过电子邮件发送或以其他方式处理它。

<?php
  // The global $_POST variable allows you to access the data sent with the POST method by name
  // To access the data sent with the GET method, you can use $_GET
  $say = htmlspecialchars($_POST['say']);
  $to  = htmlspecialchars($_POST['to']);

  echo  $say, ' ', $to;
?>

本示例显示一个包含我们发送的数据的页面。您可以在我们的示例php-example.html文件中看到它的实际运行情况-该文件包含与我们之前看到的相同的示例表单,带有一个methodof POST和一个actionof php-example.php

提交后,它将表单数据发送到php-example.php,其中包含在上面的块中看到的PHP代码。

执行此代码后,浏览器中的输出为Hi Mom

注意:当您将示例加载到本地浏览器中时,该示例将无法工作-浏览器无法解释PHP代码,因此,提交表单后,浏览器将只为您下载PHP文件。

为了使其正常工作,您需要通过某种PHP服务器运行该示例。

对于本地PHP测试,不错的选择是MAMP(Mac和Windows)和AMPPS(Mac,Windows,Linux)。

另请注意,如果您正在使用MAMP却未安装MAMP Pro(或者MAMP Pro演示时间试用版已过期),则可能无法使其正常工作。

为了使其再次正常运行,我们发现您可以加载MAMP应用,然后选择菜单选项MAMP > 首选项 > PHP,然后将“标准版本:”设置为“ 7.2.x”(x会有所不同,具体取决于您安装的版本)。

示例:Python

本示例说明了如何使用Python进行相同的操作-在网页上显示提交的数据。这使用Flask框架渲染模板,处理表单数据提交等(请参阅python-example.py)。

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def form():
    return render_template('form.html')

@app.route('/hello', methods=['GET', 'POST'])
def hello():
    return render_template('greeting.html', say=request.form['say'], to=request.form['to'])

if __name__ == "__main__":
    app.run()

 

上面的代码中引用的两个模板如下(如果您尝试自己运行示例,则它们必须templates位于与python-example.py文件位于同一目录的子目录):

  • form.html:与我们在POST方法部分中看到的表单相同,action设置为{{ url_for('hello') }}这是一个Jinja2模板,基本上是HTML,但是可以包含对花括号中包含的运行Web服务器的Python代码的调用。url_for('hello')基本上是说“重定向到/hello提交表单的时间”。
  • greeting.html:此模板仅包含一行,该行呈现在呈现时传递给它的数据的两位。这是通过hello()上面看到函数完成的,该函数在/helloURL导航到时运行

注意:同样,如果您只是尝试直接将其加载到浏览器中,则此代码将不起作用。Python与PHP的工作方式略有不同-要在本地运行此代码,您需要先安装Python / PIP,然后使用来安装Flask pip3 install flask此时,您应该可以使用来运行示例python3 python-example.py,然后localhost:5000在浏览器中导航到


 

其他语言和框架

您可以使用许多其他服务器端技术进行表单处理,包括Perl,Java,.Net,Ruby等。只需选择最喜欢的一种即可。

也就是说,值得注意的是,直接使用这些技术非常罕见,因为这可能很棘手。

使用许多使处理表单更容易的高质量框架中的一种更为常见,例如:

值得注意的是,即使使用这些框架,使用表单也不一定容易

但是,这比尝试从头开始编写所有功能要容易得多,并且可以节省大量时间。

注意:教您任何服务器端语言或框架都超出了本文的范围。如果您想学习它们,以上链接将为您提供一些帮助。


 

一种特殊情况:发送文件

使用HTML表单发送文件是一种特殊情况。

文件是二进制数据(或被认为是二进制数据),而所有其他数据是文本数据。

因为HTTP是文本协议,所以处理二进制数据有特殊要求。

enctype属性

此属性使您可以指定Content-Type提交表单时所生成的请求中所包含HTTP标头的值

此标头非常重要,因为它告诉服务器正在发送哪种数据。默认情况下,其值为application/x-www-form-urlencoded用人类的话来说,这意味着:“这是已被编码为URL参数的表单数据。”

如果要发送文件,则需要执行三个附加步骤:

  • method属性设置为POST因为文件内容不能放在URL参数中。
  • 将值设置为enctypemultipart/form-data因为数据将分为多个部分,每个文件一个,再加上表单主体中包含的文本数据一个(如果文本也输入到表单中)。
  • 包括一个或多个<input type="file">控件,以允许您的用户选择将要上传的文件。

例如:

<form method="post" action="https://www.foo.com" enctype="multipart/form-data">
  <div>
    <label for="file">Choose a file</label>
    <input type="file" id="file" name="myFile">
  </div>
  <div>
    <button>Send the file</button>
  </div>
</form>

注意:可以为服务器配置文件和HTTP请求的大小限制,以防止滥用。


 

安全问题

每次将数据发送到服务器时,都需要考虑安全性。

到目前为止,HTML表单是最常见的服务器攻击媒介(可能发生攻击的地方)。

这些问题永远不会来自HTML表单本身,而是来自服务器如何处理数据。

我们在服务器端学习主题网站安全性文章详细讨论了许多常见攻击和针对这些攻击的潜在防御措施。

您应该检查一下该文章,以了解可能的情况。


 

偏执:永远不要信任您的用户

那么,您如何应对这些威胁?这是远远超出本指南的主题,但是需要牢记一些规则。

最重要的规则是:永远不要信任您的用户,包括您自己;即使是受信任的用户也可能被劫持。

必须检查和清理服务器上的所有数据。总是。没有例外。

  • 逃避潜在危险的角色您应谨慎使用的特定字符取决于使用数据的上下文和所使用的服务器平台,但是所有服务器端语言均具有此功能。需要注意的是看起来像可执行代码(例如JavaScriptSQL命令)的字符序列
  • 限制输入的数据量以仅允许必要的数据
  • 沙盒上传的文件将它们存储在其他服务器上,并仅允许通过其他子域访问文件,甚至允许通过完全不同的域访问文件。

如果遵循这三个规则,则应该避免很多/大多数问题,但是让有能力的第三方执行安全检查始终是一个好主意。

不要以为您已经看过所有可能的问题。


 

摘要

如上所述,发送表单数据很容易,但是保护应用程序却很棘手。

请记住,前端开发人员不是应该定义数据安全模型的开发人员,可以执行客户端表单验证,但是服务器无法信任此验证,因为它无法真正知道什么确实发生在客户端。

如果按顺序完成了这些教程,那么您现在知道如何标记和设置表单样式,进行客户端验证以及有关提交表单的一些想法。


 

也可以看看

如果您想了解有关保护Web应用程序安全的更多信息,可以深入研究以下资源:

  

posted @ 2020-05-06 12:14  emdzz  阅读(355)  评论(0编辑  收藏  举报