阅读 592

(Ⅱ)表单相关属性、CSRF 攻击 | ③ HTML 表单详解

原创:itsOli  @前端一万小时

本文首发于公众号「前端一万小时」

本文版权归作者所有,未经授权,请勿转载!

本文节选自“语雀”私有专栏「前端一万小时 | 从零基础到轻松就业」
复制代码


🔗紧接上篇文章

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>HTML 表单</title>
  <style type="text/css">
    #txa {
      width: 300px;
      height: 200px;
      margin-left: -12px;
    }
  </style>
</head>
<body>
  <div class="login">
    <input type="text" name="sex"> <!-- ❗️注释 1 -->
    <form action="/getinfo" method="get"> <!-- ❗️注释 2 -->
      <div class="username"> <!-- ❗️注释 3 -->
        <label for="username">姓名</label> <!-- ❗️注释 4 -->
        <input id="username"  type="text" name="username" value="Oliver"> <!-- ❗️注释 5 -->

      </div>
      <div class="password">
        <label for="password" >密码</label>

        <input id="password" type="password" name="password" placeholder="输入密码"> <!-- ❗️注释 6 -->

      </div>
      <div class="sex">
        <label>性别</label> <!-- ❗️注释 7 -->
        <input type="radio" name="sex" value="男" checked><!-- ❗️注释 8 -->
        <input type="radio" name="sex" value="女"></div>
      <div class="orientation">
        <label>取向</label>
        <input type="radio" name="orientation" value="男"><input type="radio" name="orientation" value="女" checked></div>
      <div class="hobby">
        <label>爱好</label>
        <input type="checkbox" name="hobby" value="reading" checked>读书 <!-- ❗️注释 9 -->
        <input type="checkbox" name="hobby" value="design" checked>室内设计
      </div>
      <div>
        <label for="txa">评论:</label>
        <textarea id="txa" name="article">是个好人!                                  
        </textarea> <!-- ❗️注释 10 -->
      </div>
      <div class="file">
        <input type="file" name="myfile" accept="image/png"> <!-- ❗️注释 11 -->
      </div>  
      <div class="mycar">
        <label>我的 car</label>
        <select name="mycar"> <!-- ❗️注释 12 -->
          <option value="三菱" selected>三菱</option> <!-- ❗️注释 13 -->
          <option value="奥迪">奥迪</option>
          <option value="MINI">MINI</option>
        </select>
        <input type="submit" value="提交"> <!-- ❗️注释 14 -->
        <input type="button" value="不提交"> <!-- ❗️注释 15 -->
        <input type="reset" value="重置输入"> <!-- ❗️注释 16 -->
        <input type="hidden" name="csrf" value="123456oliver"> <!-- ❗️注释 17 -->
      </div>
    </form>
  </div>
</body>
</html>
复制代码

注释 5:

<label for="username">姓名</label> <!-- 注释 4 -->

<input id="username"  type="text" name="username" value="Oliver"> <!-- 注释 5 -->
复制代码
  • type="text",这个输入框是用于输入单行文本。我们使用 <input> 元素来创建一些不同的控件,type 属性确定了这是什么类型的控件;

  • name="username" ,绝大多数表单元素都需要一个名字,相当于用户输入数据的一个标识符。后台服务器脚本将使用这个元素名,并提取里边的参数(见:注释 2,表单是怎样提交给后台的);

  • value="Oliver",这里我输入例如一个初始值——Oliver,我们可以输入或不输入任何初始文本(例如:value="" )。

注释 6:

<div class="password">
  <label for="password">密码</label>

  <input id="password" type="password" name="password" placeholder="输入密码"> <!-- 注释 6 -->

</div>
复制代码
  • type="password" ,这个输入框是用于输入密码;

  • placeholder="输入密码" ,这个属性用阴影文字来引导用户在框里“输入密码”。

注释 7:

<div class="sex">
  <label>性别</label> <!-- 注释 7 -->
  <input type="radio" name="sex" value="男" checked>男 <!-- 注释 8 --> 
  <input type="radio" name="sex" value="女"></div>
复制代码

单纯用了 label,里边没有 for,与之对应的 input 里边也没有 id。因为这个 input 是“单选框”类型,没有必要点击文字(性别)就选择或输入。

注释 8:

<div class="sex">
  <label>性别</label>                                   <!-- 注释 7 -->
  <input type="radio" name="sex" value="男" checked>男  <!-- 注释 8 --> 
  <input type="radio" name="sex" value="女"></div>
复制代码
  • type="radio" ,这个是“单选钮输入”,用于单选;

  • name 都是 sex,我们单选提交后,后台脚本在提取各个 name 的参数时,就会对应的 sex = 男/女;

……value="男" checked>男
……value="女">女
复制代码

因为是勾选,没有在输入框输入东西,如果没有 value 值,那么用户只勾选后提交,我们后台是没有东西的。所以,必须手动添加 value 值,让勾选后,后台可以显示对应勾选的 value 值;

  • checked 是指这里默认先勾选上。

注释 9:

<div class="hobby">
  <label>爱好</label>
  <input type="checkbox" name="hobby" value="reading" checked>读书 <!-- 注释 9 -->
  <input type="checkbox" name="hobby" value="tour" checked>旅游
  <input type="checkbox" name="hobby" value="design" checked>室内设计
</div>
复制代码
  • type="checkbox" ,这个是“复选框”,用于多选;

  • 同理 type="radio" ,name 都是 hobby;

  • 同理由于都是勾选,因此手动添加 value 值。

注释 10:

<div>
  <label for="txa">评论:</label>
  <textarea id="txa" name="article">是个好人!                                  
  </textarea> <!-- 注释 10 -->
</div>
复制代码
  • textarea,这个是多行文本输入,区别于单行文本输入 type="text"

  • 由于 <textarea> 是一个闭合的标签,因此初始值(是个好人)要写在标签里。

注释 11:

<div class="file">
  <input type="file" name="myfile" accept="image/png"> <!-- 注释 11 -->
</div>  
复制代码
  • type="file" ,这个是用于文件上传,如上传身份信息等;

  • accept="image/png" ,accept 属性可以用来约束上传文件的格式。例如这里只能上传 image/png (但实际工作中,我们前端这样单方面的限制是不靠谱的,还需要后端也做相应的限制)。

注释 12、注释 13:

<div class="mycar">
  <label>我的 car</label>
  <select name="mycar">   
      <option value="三菱" selected>三菱</option> 
      <option value="奥迪">奥迪</option>
      <option value="MINI">MINI</option>
  </select>
复制代码
  • 这个写法就不再是 input 了,而是 select 和 option 的结合;

  • 这个是用于“在下拉菜单中选择”;

  • 这里的 value 值的手动添加也同理于 type="radio"type="checkbox" 中的 value;

  • selected 可以用来“预勾选”。

注释 14、15、16:

<input type="submit" value="提交"> <!-- 注释 14 -->
<input type="button" value="不提交"> <!-- 注释 15 -->
<input type="reset" value="重置输入"> <!-- 注释 16 -->
复制代码
  • type="submit"type="reset"type="button" 都是可以点击的按钮;

  • 有 value 值或没有 value 值得区别主要在于:这个按钮上是否有与 value 对应的相关文字。

注释 17:

<input type="hidden" name="csrf" value="123456oliver">
复制代码
  • 这一组代码在页面显示上没有任何效果,但点完“提交”后,这组代码里边的相关参数是会提交给后台的;

  • 这组代码的作用:

  1. 暂存一些信息。比如在 <input type="hidden" name="_" value="_"> 里边埋了一个值,下次我们要用的时候,就直接可以定位到这个元素去获取它的值,获取到后就可以用了,但用户什么都不知道;

  2. 由于可以暂存信息,那么在使用一些安全策略时,可以用到这个功能——CSRF 攻击。

先复习相关文章: 《从零基础到轻松就业 | 老生常谈的从 URL 输入到页面展现背后发生的事》

比如打开一个页面,实际这个页面是写好的模板,然后后端往里边填充数据,填充好后让你看得到。

换句话说,这个页面是后端处理后得到的页面。那假如说,后端在渲染这个页面给我们时(返回给浏览器之前),他就通过这种方式在这里加上这个值—— <input type="hidden" name="csrf" value="123456oliver"> ,他把这个东西写好后发给你,发给你之后,你看到的页面表面上没什么特别的变化,可实际上有一个点已经埋下了—— name="csrf" value="123456oliver"

接下来,用户该干什么还是继续干,填写用户名、密码等,填写完后点击“提交”。当用户点击“提交”按钮的时候,用户所填写的所有信息都会提交给后台,同时会提交 <input type="hidden" name="csrf" value="123456oliver"> 里的这个值:csrf=123456oliver

提交给后台后,后台就可以做个“校验”,看看这个值对不对,如果这个值是对的,那你用户的提交是安全的。

假如说没有这样一个参数、接口,那任何人都可以伪造一个这样的页面。比如说他知道我们的请求地址(action 的值),就可以用 method 发送一个 GET/POST 请求,把所有的参数都发进去,那就相当于修改了数据库。

但如果我们有这个值—— csrf=123456oliver ,而他没有这样一个值,或得到的值是错的,那他即使发送了这些数据,服务器也是不认可的。

只有当他发的这个值是对的,才能说明他有这个权限,表示他是一个合法的用户。这样就可以阻止 CSRF 攻击。

当然,CSRF 攻击这个东西还涉及到 Cookie 的校验等,后续再作相关的文章讲解。



后记: 知识点很多、很杂,但静下心来,用两个显示器,一边把本文代码拷贝放到 JS Bin 里边运行,一边对着本文的注释一行行把代码理顺,最后会发现不过如此。

前端的学习更多的是耐力的考验,有兴趣固然重要,但不付诸时间和耐力是不行的。

祝好,qdywxs ♥ you!

关注下面的标签,发现更多相似文章
评论