热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【译】发送表单数据

这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是

这是原文链接:sending form data

许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是了解一些细节还是很重要的,以避免损坏您的服务器或者给您的用户带来麻烦。

发送数据到哪?

客户端/服务器架构

web是基于非常简单的客户端/服务器架构的,可以总结为一下两点:

  1. 客户端(通常是浏览器)通过HTTP协议发送请求给服务器(大部分服务器就是Apache,Nginx,IIS,Tomcat)
  2. 服务器同样使用HTTP协议来返回响应

客户端/服务器端架构

在客户端,没有比表单更方便而且用户友好的方式来配置HTTP请求去发送数据到服务器端了。这使得用户可以通过HTTP请求来传递信息。

在客户端:定义怎样发送数据

表单元素定义了怎样发送数据。其所有属性就是被设计用来配置HTTP请求的。最主要的两个属性是action和method。

关于action属性
该属性定义了数据被发送到哪。其值必须是合法的URL。如果没有提供该属性,那么数据发送到当前页面。

例子

这个例子中,数据被发送到http://foo.com

这个例子中,数据被发送到相同的服务器中,但是与当前页面不同的URL

如果没有指定该属性,那么数据被发送到当前页面

许多以前的网页中使用下面的代码来指明数据应该被发送到当前页面,应为在HTML5之前,该属性是必须的,现在已经没有必要了这样写了

注意:可以指定URL使用https协议。如果这样做了,那么即使表单本身处于不安全的网页中(使用http协议),表单数据也会被加密。另一方面,如果表单本身处于安全网页中,但是指定URL使用不安全的http协议,那么每次当用户提交数据时,浏览器都会显示不安全的警告给用户,因为数据没有被加密。

关于method属性

该属性定义了数据怎样被发送。HTTP协议定义了许多种request;表单数据至少可以通过两种方法来发送:GET和POST。

为了理解两种发送方法的不同,我们先回顾一下HTTP工作原理。每次当你想要获取一个网络上的资源,浏览器会发送一个请求。这个请求包含两个部分:header和body。其中header包含了一系列的关于浏览器能力的全局元数据,body则是包含一些发送到服务器端的信息(只用部分发送方法的请求有body部分,有些请求没有body部分)。

关于GET方法
GET方法说明浏览器想要服务器端返回一个资源:“嘿,服务器,给我返回这个资源”。这种请款下,浏览器发送的请求没有body部分。因为如果表单采用这种方法发送数据,数据会被添加到URL后面,所以body是空的。

例子

考虑下面的表单:


如果使用GET方法,那么请求应该是这样的:

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

关于POST方法
POST方法有些不同。浏览器希望服务器处理这些数据:“嘿,服务器,看看这些数据然后给我一个结果”。发送的数据处在请求的body部分。

例子

考虑下面的表单(和上面的一样)


现在使用POST方法,那么请求应该是这样的:

POST / HTTP/1.1
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13say=Hi&to=Mom

Content-Length字段指明body的大小,Content-Type字段指明发送到服务器端的资源类型(其实就是编码方式)。

当然,HTTP协议从来不会显示给用户(不过可以通过浏览器的开发者工具来查看)。唯一显示给用户的就是URL。所以在GET方法中,用户可以从网址栏中看见数据,但是在POST方法中,就看不见了。这一点非常重要:

  1. 如果将要发送用户名和密码(或者其他敏感信息),一定不能使用GET方法,否则就会在地址栏显示出来。
  2. 如果将要发送巨量数据,最好使用POST方法,应为某些浏览器会限制URL的长度,并且许多服务器也会限制可以接收的URL长度。

在服务器端:解析并获取数据

不管采用哪种请求方法,服务器端会接收到一个字符串,然后解析该字符串,得到一系列的键值对。获取这些数据的方式取决于你选择的开发平台和特定开发框架。不同的技术同样影响到重复键的处理方法;一般情况下,后接受到的优先级更大,会覆盖掉之前的数据。

例子:原生PHP

PHP提供了一些全局对象去获取这些数据。假设我们使用POST方法提交数据,下面的例子仅仅是获取这些数据然后展示给用户。当然,怎样处理这些数据取决于你。你可以显示数据,存储数据,发送邮件或者其他方式。

上面例子的结果是:

Hi Mom

例子:原生Python

本例子使用Python实现相同的功能--显示网页提供的数据。例子中使用CGI Python package来获取数据。

#!/usr/bin/env python
import html
import cgi
import cgitb; cgitb.enable() # for troubleshootingprint("Content-Type: text/html") # HTTP header to say HTML is following
print() # blank line, end of headersform = cgi.FieldStorage()
say = html.escape(form["say"].value);
to = html.escape(form["to"].value);print(say, " ", to)

显示结果和上面的例子一样:

Hi Mom

其他语言和框架

还有许多其他的服务端技术可以处理表单,包括Perl,Java,.Net,Ruby等等。选择你最喜欢的就好了。但是也没有必要直接使用这些技术去处理表单,因为会比较繁琐。更通常的做法是选择一种框架来辅助处理表单,比如:

  • Symfony for PHP
  • Django for Python
  • Ruby On Rails for Ruby
  • Grails for Java

虽然使用这些框架来处理表单不一定就是非常容易,但是总是好一些,并且可以节省大量时间。

一种特殊情况:发送文件

发送文件对表单来说是一种特殊情况。文件是二进制数据--至少被当作二进制数据--但是其他数据都是文本数据。因为HTTP协议是一种文本协议,所以处理二进制数据是特殊需求了。

enctype属性

该属性可以指定Content-Type字段的值。该字段非常重要,因为可以让服务器端识别出发送的数据类型(编码类型)。默认值是application/x-www-urlencoded。对人类而言,这意味着:“表单数据已经被编码成URL形式了”。

如果我们想要发送文件,应该需要做两件事:

  1. 设置method属性为POST,因为文件内容不能放到URL中。
  2. 设置enctype属性为multipart/form-data,这样文件会被分割成很多部分发送到服务器。

举个例子:


注意:有些浏览器的input元素支持multiple属性,从而支持一个input元素可以发送多个文件。服务器端怎样处理这些文件完全依赖与服务器端选择的技术。前面也提到过,使用框架来处理这些东西会稍微轻松些。

警告:许多服务器都限制了上传文件的大小和HTTP请求的大小,以防止滥用资源。和服务器管理员确定这个限制的大小是非常重要的。

安全问题

当你每次发送数据给服务器时,你都应该考虑安全问题。HTML表单是服务器的主要威胁之一。不过问题并不是来源于表单本身,而是服务器如何处理表单数据。

常见安全漏洞

以下是一些众所周知的安全问题:

XSS和CSRF

跨站点脚本攻击(XSS)和跨站点请求伪造(CSRF)是常见的攻击类型,这通常发生在服务器接收用户的数据然后再次显示这些数据给用户。

XSS使得攻击者可以注入客户端脚本到网页中。一个XSS漏洞可能会让攻击者可以绕过访问控制,比如同源策略。这些攻击的影响可大可小,可以是比较小的干扰,也可以是重大安全风险。

CSRF和XSS有些相似--因为他们都需要注入客户端脚本到网页中--但是CSRF的目的又不一样。CSRF攻击者会提升自己的特权(比如网站管理员),然后就可以做一些本来没有权利的操作,比如发送数据给不信任的用户。

XSS攻击利用用户对网站的信任,CSRF攻击利用网站对用户的信任。

为避免这些攻击,你应该检查用户发送到服务器的所有数据,而且不应该显示用户提供的HTML内容。相反,你应该处理这些数据而不是一字不变的显示这些数据。如今大部分框架都实现了基本的HTML字符过滤,比如过滤掉,,。这可以降低风险,但还是不能完全避免掉。

SQL注入

SQL注入是一种尝试操作网站数据库的一种攻击。攻击者通常会发送SQL请求并期望服务器去执行它(其实就是存储数据),这也是服务器的主要威胁之一。

这种攻击的后果是非常严重的,轻一点就是数据丢失,严重的就是特权提升到可以操作所有服务器资源。这种威胁是非常严峻的,所以你永远不应该直接存储用户提交的数据,而是需要做一些检查以及消毒工作(比如在PHP/MySQL应用中使用mysql_real_escape_string())。

HTTP header注入 以及 email 注入

如果你使用表单数据来建立HTTP header或者email,那么就有可能发生这些攻击。他们不会直接攻击服务器或者影响到用户,但却是更深层次问题的后门,比如会话劫持或者钓鱼攻击。

这些攻击大部分都是静悄悄的,但是却会将你的服务器变为肉鸡。

警记:永远不要相信你的用户

那么怎样处理这些威胁呢?这些内容已经超出本章内容了,但是仍然有一些规则需要牢记在心中。最最重要的规则就是:永远不要相信用户,包括自己;因为一个可信任的用户也可能被劫持。

所有到达服务器的数据都需要检查和消毒,总是这样做,不要存在例外。

  • 转义潜在的危险的字符。根据数据内容的不同以及部署平台的不同,需要小心的字符也有所区别。但是所有服务器端语言都有相关的函数来处理这种转义。
  • 限制数据的大小以及必须的类型。
  • 上传文件到沙箱(存储这些文件到一个不同的服务器,而且只允许通过一个不同的子域名来访问文件,甚至最好是完全不同的域名来访问文件)。

如果你遵守上面三条规则,你应该可以避免掉绝大部分的难题了,但是邀请第三方做一个安全审查仍然是一个好主意。永远不要假设你已经解决了所有问题。

总结

如你所见,发送表单数据是非常容易的,但是只做安全的web应用则是复杂的。要记住作为前端开发者不仅仅只是定义数据模型。我们还要做客户端的数据校验,但是服务器端仍然不能信任这些校验结果,因为服务器可没办法知道客户端的真实情况。

另请参见

下面两个链接是关于安全web应用方面的,可以继续参考学习:

  1. The Open Web Application Security Project (OWASP)
  2. Chris Shiflett's blog about PHP Security

下面是关于http方面的链接

  1. GET/POST之enctype
  2. GET vs. POST
  3. What's the difference between “Request Payload” vs “Form Data” as seen in Chrome dev tools Network tab
  4. How are parameters sent in an HTTP POST request?

个人补充

上面更多的内容是关于web安全方面的,下面补充一点method以及enctype方面的信息。

表单中method属性用来指定发送数据的方法:比如GET/POST/PUT等等
表单中enctype属性用来指定发送的数据的编码方式:比如text/plain,application/json,application/x-www-form-urlencoded,application/octet-stream,multipart/form-data等等

GET/POST/PUT最大的不同当然是语义不一样,不过这里只研究对于发送数据的影响。
GET发送的数据位于URL中的query string部分,而URL又处于请求header部分。
POST/PUT发送的数据位置倒是一样,都是位于请求body部分。

不同的method会影响到发送数据的位置,而enctype则会影响到数据的编码方式。
form元素的enctype默认值则是application/x-www-form-urlencoded,所以发送的数据可能长得像这样:

username=name123&password=pass456&age=12&sex=1

注意这种编码形式和GET/POST/PUT是没有关系的。只不过如果是GET方法,那么URL加上问号(?)再加上数据拼接起来。如果是POST/PUT方法,那么数据就存放在请求body部分。

对于jquery中的ajax方法的contentType默认值也是application/x-www-form-urlencoded。
而在backbone中,Backbone.sync方法中有一段代码会做出判断,可能会将contentType设置为application/json。

先说说multipart/form-data,一般在上传文件的时候,需要将表单的enctype设置为multipart/form-data。正如上面译文中所讲,文件属于二进制数据,application/x-www-form-urlencoded是不适用的。
不过这种编码方式过于复杂,不像上面的urlencoded编码,只需要两次分割字符串就能得到所有的键值对。对于这种复杂的编码方式,我们自己去解析数据,是很难的,幸好已经有开源的库完成了这一部分功能。
对于单文件上传也许还好,自己了解编码方式以后,解析起来也不是很难。难点在于多文件上传,甚至还有普通表单控件混在其中。

再说说application/json,据我理解urlencoded编码方式只适用于扁平化的键值对,对于嵌套过深的json对象就很难编码了。而application/json就非常适用于嵌套过深的json数据。
在chrome的开发者工具中的network页签中,显示发送数据位于Request Payload。而如果是application/x-www-form-urlencoded,就会显示发送数据位于Form Data。

实际上是可以自定义contentType的,也就是自定义编解码的规则。不过只针对ajax有效,对于form元素是不起作用的。因为form元素的编码规则有浏览器控制。而对于ajax,我们完全可以自己编码,然后在服务器端自己解码。

最后一点,如果服务器端不能理解Content-Type指定的编码方式,那么应该返回415错误。

转:https://www.cnblogs.com/3tree/p/4584302.html



推荐阅读
  • 本文介绍了 PHP 的基本概念、服务器与客户端的工作原理,以及 PHP 如何与数据库交互。同时,还涵盖了常见的数据库操作和安全性问题。 ... [详细]
  • 探讨了在HTML表单中使用元素代替进行表单提交的方法。 ... [详细]
  • ArcBlock 发布 ABT 节点 1.0.31 版本更新
    2020年11月9日,ArcBlock 区块链基础平台发布了 ABT 节点开发平台的1.0.31版本更新,此次更新带来了多项功能增强与性能优化。 ... [详细]
  • 基于SSM框架的在线考试系统:随机组卷功能详解
    本文深入探讨了基于SSM(Spring, Spring MVC, MyBatis)框架构建的在线考试系统中,随机组卷功能的设计与实现方法。 ... [详细]
  • binlog2sql,你该知道的数据恢复工具
    binlog2sql,你该知道的数据恢复工具 ... [详细]
  • Asynchronous JavaScript and XML (AJAX) 的流行很大程度上得益于 Google 在其产品如 Google Suggest 和 Google Maps 中的应用。本文将深入探讨 AJAX 在 .NET 环境下的工作原理及其实现方法。 ... [详细]
  • JavaScript 跨域解决方案详解
    本文详细介绍了JavaScript在不同域之间进行数据传输或通信的技术,包括使用JSONP、修改document.domain、利用window.name以及HTML5的postMessage方法等跨域解决方案。 ... [详细]
  • 为何Compose与Swarm之后仍有Kubernetes的诞生?
    探讨在已有Compose和Swarm的情况下,Kubernetes是如何以其独特的设计理念和技术优势脱颖而出,成为容器编排领域的领航者。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
  • 本文介绍了ADO.NET框架中的五个关键组件:Connection、Command、DataAdapter、DataSet和DataReader。每个组件都在数据访问和处理过程中扮演着不可或缺的角色。 ... [详细]
  • 本文探讨了在一个物理隔离的环境中构建数据交换平台所面临的挑战,包括但不限于数据加密、传输监控及确保文件交换的安全性和可靠性。同时,作者结合自身项目经验,分享了项目规划、实施过程中的关键决策及其背后的思考。 ... [详细]
  • 菜鸟物流用户增长部现正大规模招聘P6及以上级别的JAVA工程师,提供年后入职选项。 ... [详细]
  • 流处理中的计数挑战与解决方案
    本文探讨了在流处理中进行计数的各种技术和挑战,并基于作者在2016年圣何塞举行的Hadoop World大会上的演讲进行了深入分析。文章不仅介绍了传统批处理和Lambda架构的局限性,还详细探讨了流处理架构的优势及其在现代大数据应用中的重要作用。 ... [详细]
  • 如何高效解决Android应用ANR问题?
    本文介绍了ANR(应用程序无响应)的基本概念、常见原因及其解决方案,并提供了实用的工具和技巧帮助开发者快速定位和解决ANR问题,提高应用的用户体验。 ... [详细]
author-avatar
好人杨华_840
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有