Python+Django+SAE系列教程14-----使表单更安全

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介:

还记得我们上一章提到过的加入页面吗?


加入完以后我们注意一下地址栏:


表单里的数据赤裸裸的显示在了地址栏中,这时候假设我们改动一下内容


刷新,这样数据库里面就会又加入了一条数据,也就是说用户假设知道表单的结果页的连接,就能够不通过我们的表单。随意加入数据了,这样当然不是我们想要的结果。


这种结果是由于我们在表单中使用了get的方式来传递数据,这时我们应该想到採用post的方法,postget更加安全,我们来改动一下模板页面,注意这里:



以下是表单模板Classroom_Add.html的代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
    <title>数据库操作简单表的加入</title>
</head>
<body>
    <h1>这里是Classroom的加入页面</h1>
    {% if error %}
        <p style="color: red;">请输入班级名称和导师姓名</p>
    {% endif %}
   <form action="" method="post">
   {% csrf_token %} 
        <table border="1" cellpadding="10">
          <tr>
            <td align="center">项目</td>
            <td align="center">内容</td>
          </tr>
          <tr>
            <td align="right">班级名称:</td>
            <td><input type="text" name="name"></td>
          </tr>
          <tr>
            <td align="right">导师姓名:</td>
            <td><input type="text" name="tutor"></td>
          </tr>
          <tr>
            <td colspan="2"><input type="submit" value="加入"></td>
          </tr>
        </table>
  </form>
  
</body>
</html>

get方法改动为post后,我们当然也要改动一下视图,之前的get方法是这种:

def ClassroonAdd(request):
    if 'name' in request.GET and request.GET['name'] and 'tutor' in request.GET and request.GET['tutor']:
        name = request.GET['name']
        tutor = request.GET['tutor']
        c = ClassRoom(name=name,tutor=tutor)
        c.save()
        return render_to_response('person/Classroom_Add_results.html',
            {'name': name})
    else:
        return render_to_response('person/Classroom_Add.html', {'error': True})

改动以后的pose方法是这种 :

def ClassroonAdd(request):
    if request.POST.has_key('name')  and request.POST.has_key('tutor') :
        name = request.POST['name']
        tutor = request.POST['tutor']
        c = ClassRoom(name=name,tutor=tutor)
        c.save()
        
        return render_to_response('person/Classroom_Add_results.html',
            {'name': name},context_instance=RequestContext(request))
    else:
        return render_to_response('person/Classroom_Add.html', {'error': True},context_instance=RequestContext(request))

这时候我们在来測试一下:



地址栏里面的參数不见了!

我们在前一节讲的样例中另一个表单:就是改动页面。我们使用同样的方法来进行改动。改造Classroom_Modify.html模板:

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
    <title>数据库操作简单表的改动</title>
</head>
<body>
    <h1>这里是Classroom--{{name}}的改动页面</h1>
    {% if error %}
        <p style="color: red;">请输入班级名称和导师姓名</p>
    {% endif %}
    <form action="" method="post">
   {% csrf_token %} 
        <table border="1" cellpadding="10">
          <tr>
            <td align="center">项目</td>
            <td align="center">内容</td>
          </tr>
          <tr>
            <td align="right">班级名称:</td>
            <td><input type="text" name="name" value="{{name}}"></td>
          </tr>
          <tr>
            <td align="right">导师姓名:</td>
            <td><input type="text" name="tutor" value="{{tutor}}"></td>
          </tr>
          <tr>
            <td colspan="2">
            <input type="hidden" name="id" value="{{id}}">
            <input type="submit" value="改动">
            <input type="button" value="返回" onClick="location.href='../../list'">
            </td>
          </tr>
        </table>
  </form>
</body>
</html>

改动视图页面:

def ClassroonModify(request,id1):
    cursor=connection.cursor()
    Classroon=ClassRoom.objects.get(id=id1)
    old_name = Classroon.name
    old_tutor = Classroon.tutor
    cursor.close()

    if request.POST.has_key('name')  and request.POST.has_key('tutor') :
        new_name = request.POST['name']
        new_tutor = request.POST['tutor']
        Classroon.name=new_name
        Classroon.tutor=new_tutor
        Classroon.save()
        return render_to_response('person/Classroom_Modify_results.html',
            {'old_name': old_name,'old_tutor':old_tutor,'new_name':new_name,'new_tutor':new_tutor},context_instance=RequestContext(request))
    else:
        return render_to_response('person/Classroom_Modify.html', {'error': True,'id':id1,'name':old_name,'tutor':old_tutor},context_instance=RequestContext(request))

完毕。这样我们就把曾经的get方法改动成了post,在一定程度上保证了表单的安全。

以下的问题就是直接訪问改动页面或者删除页面呢,如这样:

直接在浏览当中输入地址,就能够删除和打开改动页面了。这样太危急了。全部这就要用到我们在11章 的样例http://blog.csdn.net/hemeng1980/article/details/25239713中的GetHTTP_REFERER了。只是须要注意的是一下情况:

一、可以取到HTTP_REFERER的情况为下面几种:

 

1.直接用<a href>

2.用Submit<input type=image>提交的表单(POST or GET)

3.使用Jscript提交的表单(POST or GET)

 

二、不能取到的情况有下面几种:

 

1.从收藏夹链接

2.单击”主页”或者自己定义的地址

3.利用Jscriptlocation.href or location.replace()

4.在浏览器直接输入地址

5<%Response.Redirect%>

6<%Response.AddHeader%><meta http-equiv=refresh>转向

7.用XML载入地址

 

而我就犯了不能取到的第三种错误。所以我们要吧原来的button改动成为连接(A标签)。改动Classroom_List.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
    <title>数据库操作简单表的加入</title>
</head>
<body>
    <h1>这里是Classroom的管理页面</h1>
        <table border="1" cellpadding="10">
          <tr>
            <td align="center">序号</td>
            <td align="center">班级名称</td>
            <td align="center">导师姓名</td>
            <td align="center">操作</td>
          </tr>
          {% for myclass in ClassroonList%}
          <tr>
            <td align="right">{{ myclass.id }}</td>
            <td align="right">{{ myclass.name }}</td>
            <td align="right">{{ myclass.tutor }}</td>
            <td align="right">
            <a href="../modify/{{ myclass.id }}">改动</a>
            <a href="../delete/{{ myclass.id }}">删除</a>
        
            </td>
          </tr>
          {% endfor %} 
        </table>
</body>
</html>

接下来我们改动一下视图:

def ClassroonModify(request,id1):

    GetHost=request.get_host()
    try:  
        GetHTTP_REFERER = request.META['HTTP_REFERER']  
    except KeyError:  
        GetHTTP_REFERER = 'unknown'
        
    if GetHTTP_REFERER!='unknown' and GetHTTP_REFERER.find(GetHost)>0:
        cursor=connection.cursor()
        Classroon=ClassRoom.objects.get(id=id1)
        old_name = Classroon.name
        old_tutor = Classroon.tutor
        cursor.close()
        if request.POST.has_key('name')  and request.POST.has_key('tutor') :
            new_name = request.POST['name']
            new_tutor = request.POST['tutor']
            Classroon.name=new_name
            Classroon.tutor=new_tutor
            Classroon.save()
            return render_to_response('person/Classroom_Modify_results.html',
                {'old_name': old_name,'old_tutor':old_tutor,'new_name':new_name,'new_tutor':new_tutor},context_instance=RequestContext(request))
        else:
            return render_to_response('person/Classroom_Modify.html', {'error': True,'id':id1,'name':old_name,'tutor':old_tutor},context_instance=RequestContext(request))
    else:
        return render_to_response('person/Error.html')

不要忘了加入一个Error.html'

<html>
<head>
    <title>查询用户结果页</title>
</head>
<body>
    <table border="1" cellpadding="5"><tr>
      <td>非法操作</td></tr>
      <tr>
        <td><a href="http://127.0.0.1:8000/ClassRoom/list/">点击返回</a></td>
      </tr>
    </table>
</body>
</html>

依照相同的方法改动一下删除功能:

def ClassroonDelete(request,id1):
    
    GetHost=request.get_host()
    try:  
        GetHTTP_REFERER = request.META['HTTP_REFERER']  
    except KeyError:  
        GetHTTP_REFERER = 'unknown'
        
    if GetHTTP_REFERER!='unknown' and GetHTTP_REFERER.find(GetHost)>0:
        cursor=connection.cursor()
        Classroon=ClassRoom.objects.get(id=id1)
        old_name = Classroon.name
        Classroon.delete()
        ClassroonList=ClassRoom.objects.all()
        cursor.close()
        return render_to_response('person/Classroom_Delete_results.html',{'name':old_name})
    else:
        return render_to_response('person/Error.html')

我们做一下測试假设这时候直接输入网址:http://127.0.0.1:8000/ClassRoom/modify/48/

就会看到:

这样我们有保护了删除和改动页面的安全性。

最后另一个问题,假设加入后怎样防止刷新表单,这个功能眼下我们还没有解说到Session。先留一个伏笔把,假设对session了解的人,能够先參考这个试试 :

http://www.cnblogs.com/ken-zhang/archive/2010/12/25/1916437.html

以后我们会具体讨论这个问题的。













本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5121370.html,如需转载请自行联系原作者

相关实践学习
1分钟部署经典小游戏
本场景介绍如何使用Serverless应用引擎SAE 1分钟快速部署经典小游戏。
SAE的功能与使用入门
欢迎来到《SAE的功能与使用入门》,本课程是“云原生Serverless Clouder认证“系列中的第三阶段。课程将向您介绍阿里云Serverless应用引擎(SAE)服务相关的概念、特性与使用方式。通过课程将带您逐步深入探索Serverless世界,借助SAE服务,即使没有丰富的云计算和IT经验,也能够让开发人员在实际业务场景中便捷的掌握如何构建和部署应用程序,快速拥抱Serverless架构,将精力聚焦在应用代码和业务逻辑的实现上。 学习完本课程后,您将能够: 掌握Serverless应用引擎(SAE)的基本概念与核心优势 了解Serverless应用引擎(SAE)的核心功能 掌握使用Serverless应用引擎(SAE)的开发和部署流程 了解Serverless应用引擎(SAE)的适用场景和最佳实践 &nbsp;
相关文章
|
3月前
|
JSON 数据可视化 API
Python 中调用 DeepSeek-R1 API的方法介绍,图文教程
本教程详细介绍了如何使用 Python 调用 DeepSeek 的 R1 大模型 API,适合编程新手。首先登录 DeepSeek 控制台获取 API Key,安装 Python 和 requests 库后,编写基础调用代码并运行。文末包含常见问题解答和更简单的可视化调用方法,建议收藏备用。 原文链接:[如何使用 Python 调用 DeepSeek-R1 API?](https://apifox.com/apiskills/how-to-call-the-deepseek-r1-api-using-python/)
|
19天前
|
Python
Python教程:os 与 sys 模块详细用法
os 模块用于与操作系统交互,主要涉及夹操作、路径操作和其他操作。例如,`os.rename()` 重命名文件,`os.mkdir()` 创建文件夹,`os.path.abspath()` 获取文件绝对路径等。sys 模块则用于与 Python 解释器交互,常用功能如 `sys.path` 查看模块搜索路径,`sys.platform` 检测操作系统等。这些模块提供了丰富的工具,便于开发中处理系统和文件相关任务。
68 14
|
1月前
|
数据采集 存储 监控
Python 原生爬虫教程:网络爬虫的基本概念和认知
网络爬虫是一种自动抓取互联网信息的程序,广泛应用于搜索引擎、数据采集、新闻聚合和价格监控等领域。其工作流程包括 URL 调度、HTTP 请求、页面下载、解析、数据存储及新 URL 发现。Python 因其丰富的库(如 requests、BeautifulSoup、Scrapy)和简洁语法成为爬虫开发的首选语言。然而,在使用爬虫时需注意法律与道德问题,例如遵守 robots.txt 规则、控制请求频率以及合法使用数据,以确保爬虫技术健康有序发展。
202 31
|
1月前
|
数据采集 搜索推荐 API
Python 原生爬虫教程:京东商品列表页面数据API
京东商品列表API是电商大数据分析的重要工具,支持开发者、商家和研究人员获取京东平台商品数据。通过关键词搜索、分类筛选、价格区间等条件,可返回多维度商品信息(如名称、价格、销量等),适用于市场调研与推荐系统开发。本文介绍其功能并提供Python请求示例。接口采用HTTP GET/POST方式,支持分页、排序等功能,满足多样化数据需求。
|
1月前
|
数据采集 API 数据格式
Python 原生爬虫教程:京东商品详情页面数据API
本文介绍京东商品详情API在电商领域的应用价值及功能。该API通过商品ID获取详细信息,如基本信息、价格、库存、描述和用户评价等,支持HTTP请求(GET/POST),返回JSON或XML格式数据。对于商家优化策略、开发者构建应用(如比价网站)以及消费者快速了解商品均有重要意义。研究此API有助于推动电商业务创新与发展。
|
2月前
|
机器学习/深度学习 数据采集 数据可视化
Python/Anaconda双方案加持!Jupyter Notebook全平台下载教程来袭
Jupyter Notebook 是一款交互式编程与数据科学分析工具,支持40多种编程语言,广泛应用于机器学习、数据清洗和学术研究。其核心优势包括实时执行代码片段、支持Markdown文档与LaTeX公式混排,并可导出HTML/PDF/幻灯片等格式。本文详细介绍了Jupyter Notebook的软件定位、特性、安装方案(Anaconda集成环境与原生Python+PIP安装)、首次运行配置及常见问题解决方案,帮助用户快速上手并高效使用该工具。
|
2月前
|
SQL 关系型数据库 MySQL
milvus-use教程 python
本项目参考vanna项目,获取数据库元数据和问题SQL对,存入Milvus向量数据库,并进行相似性检索。采用m3e-large嵌入模型,通过DatabaseManager类实现数据库连接持久化,MilvusVectorStore类封装了Milvus操作方法,如创建集合、添加数据和查询。项目提供init_collections、delete_collections等文件用于初始化、删除和管理集合。所用Milvus版本较新,API与vanna项目不兼容。 [项目地址](https://gitee.com/alpbeta/milvus-use)
222 9
|
3月前
|
大数据 开发者 C++
Python语法糖详解教程
《Python语法糖详解教程》介绍了编程语言中的“语法糖”,即通过特殊语法形式简化代码,使代码更简洁、易读和高效。文章详细解析了列表推导式、字典推导式、元组解包、条件表达式、with语句和装饰器等核心语法糖,并提供了具体示例和最佳实践指南。通过这些技巧,开发者可以在保持底层功能不变的前提下,显著提升开发效率和代码质量。
143 8
|
4月前
|
IDE 测试技术 项目管理
【新手必看】PyCharm2025 免费下载安装配置教程+Python环境搭建、图文并茂全副武装学起来才嗖嗖的快,绝对最详细!
PyCharm是由JetBrains开发的Python集成开发环境(IDE),专为Python开发者设计,支持Web开发、调试、语法高亮、项目管理、代码跳转、智能提示、自动完成、单元测试和版本控制等功能。它有专业版、教育版和社区版三个版本,其中社区版免费且适合个人和小型团队使用,包含基本的Python开发功能。安装PyCharm前需先安装Python解释器,并配置环境变量。通过简单的步骤即可在PyCharm中创建并运行Python项目,如输出“Hello World”。
1469 13
【新手必看】PyCharm2025 免费下载安装配置教程+Python环境搭建、图文并茂全副武装学起来才嗖嗖的快,绝对最详细!
|
3月前
|
C语言 Python
Python学习:内建属性、内建函数的教程
本文介绍了Python中的内建属性和内建函数。内建属性包括`__init__`、`__new__`、`__class__`等,通过`dir()`函数可以查看类的所有内建属性。内建函数如`range`、`map`、`filter`、`reduce`和`sorted`等,分别用于生成序列、映射操作、过滤操作、累积计算和排序。其中,`reduce`在Python 3中需从`functools`模块导入。示例代码展示了这些特性和函数的具体用法及注意事项。