Django的csrf中间件
CSRF:跨站请求伪造Cross Site Request Forgery
CSRF的攻击流程
用户a 访问可信站点1做业务处理,此时浏览器会保存该网站的cookie,当用户a 访问不可信站点2时,如果站点2有指向站点1的链接时候,那么攻击就用可能发生
Eg:
1、包含站点1的链接,点击跳转
2、img 的src属性值是站点1的链接
3、Js加载,js里有跳转的动作
Django的解决方法
Django预防CSRF攻击的方法是在用户提交的表单中加入一个csrftoken的隐含值,这个值和服务器中保存的csrftoken的值相同
前后端的使用
后端
全局使用(禁用)
使用中间件操作
局部使用或禁用
from django.views.decorators.csrf import csrf_exempt(不使用CSRF验证), csrf_protect(使用CSRF校验)
前端
Form表单
{%csrf_token%}
Ajax 方式
<script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="//cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
function submit() {
{# 拿数据#}
var name = $("#name").val();
var num = $("#num").val();
var csrf_token = $.cookie("csrftoken");
console.log(csrf_token);
$.ajax({
url:"/t08/cz",
data:{
"name": name,
"num": num,
"csrfmiddlewaretoken": csrf_token
},
method:"post",
success: function (res) {
console.log(res);
}
})
}
使用: 后端
全局使用(禁用)
使用中间件操作
局部使用或禁用
from django.views.decorators.csrf import csrf_exempt(不使用CSRF验证),
csrf_protect(使用CSRF校验)
前端
Form表单
{%csrf_token%}
Ajax 方式
LOG
Log简介
logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:
通过log的分析,可以方便用户了解系统或软件、应用的运行情况;如果你的应用log足够丰富,也可以分析以往用户的操作行为、类型喜好、地域分布或其他更多信息;如果一个应用的log同时也分了多个级别,那么可以很轻易地分析得到该应用的健康状况,及时发现问题并快速定位、解决问题,补救损失。
Log的用途
不管是使用何种编程语言,日志输出几乎无处不再。总结起来,日志大致有以下几种用途:
- 问题追踪:通过日志不仅仅包括我们程序的一些bug,也可以在安装配置时,通过日志可以发现问题。
- 状态监控:通过实时分析日志,可以监控系统的运行状态,做到早发现问题、早处理问题。
- 安全审计:审计主要体现在安全上,通过对日志进行分析,可以发现是否存在非授权的操作
Log等级
- DEBUG最详细的日志信息,典型应用场景是 问题诊断
- INFO信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作
- WARNING当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
- ERROR由于一个更严重的问题导致某些功能不能正常运行时记录的信息 如IO操作失败或者连接问题
- CRITICAL当发生严重错误,导致应用程序不能继续运行时记录的信息
Log模块的四大组件
-
Loggers
提供应用程序代码直接使用的接口 -
Handlers
用于将日志记录发送到指定的目的位置FileHandler:logging.FileHandler;日志输出到文件 RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚 SMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址 HTTPHandler:logging.handlers.HTTPHandler;通过"GET"或者"POST"远程输出到HTTP服务器 等等
-
Filters
提供更细粒度的日志过滤功能,用于决定哪些日志记录将会被输出(其它的日志记录将会被忽略) -
Formatters
用于控制日志信息的最终输出格式%(levelno)s:打印日志级别的数值 %(levelname)s:打印日志级别的名称 %(pathname)s:打印当前执行程序的路径,其实就是sys.argv[0] %(filename)s:打印当前执行程序名 %(funcName)s:打印日志的当前函数 %(lineno)d:打印日志的当前行号 %(asctime)s:打印日志的时间 %(thread)d:打印线程ID %(threadName)s:打印线程名称 %(process)d:打印进程ID %(message)s:打印日志信息
示例
import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler(“log.txt”)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.info("Start print log")
logger.debug("Do something")
logger.warning("Something maybe fail.")
logger.info("Finish")
Django中的配置
ADMINS = (
('tom','*******@163.com'),
)
EMAIL_BACKEND ='django.core.mail.backends.smtp.EmailBackend'
SERVER_EMAIL=EMAIL_HOST_USER
#####可自定义修改
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'standard': {
'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'}
},
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
}
},
'handlers': {
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['require_debug_false'],
},
'debug': {
'level':'DEBUG',
'class':'logging.handlers.RotatingFileHandler',
'filename': os.path.join(BASE_DIR, "log",'debug.log'), #文件路径
'maxBytes':1024*1024*5,
'backupCount': 5,
'formatter':'standard',
},
'console':{
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'standard',
},
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False
},
'django.request': {
'handlers': ['debug','mail_admins'],
'level': 'ERROR',
'propagate': True,是否继承父类的log信息
},
# 对于不在 ALLOWED_HOSTS 中的请求不发送报错邮件
'django.security.DisallowedHost': {
'handlers': ['null'],
'propagate': False,
},
}
}
import logging
logger = logging.getLogger("django") # 为loggers中定义的名称
logger.info("some info...")
自定义修改
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'
},
'easy':{
'format': '%(asctime)s|%(funcName)s|%(message)s'
}
},
'filters': { #过滤条件
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
'require_debug_true':{
'()': 'django.utils.log.RequireDebugTrue', #邀要求debug是True
}
},
'handlers': {
'mail_admins': { #一旦线上代码报错 邮件提示
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['require_debug_false'],
},
'debug': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(BASE_DIR, "log", 'debug.log'), # 文件路径
'maxBytes': 1024 * 1024 * 5, #5兆的数据
'backupCount': 5, #允许有5这样的文件
'formatter': 'easy', #格式
},
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'standard',
},
},
'loggers': {
'django': {
'handlers': ['console', 'debug'],
'level': 'DEBUG',
'propagate': False
},
'django.request': {
'handlers': ['debug', 'mail_admins'],
'level': 'ERROR',
'propagate': True, #是否继承父类的log信息
},
# 对于不在 ALLOWED_HOSTS 中的请求不发送报错邮件
'django.security.DisallowedHost': {
'handlers': ['debug'],
'propagate': False,
},
}
}
邮箱
配置
EMAIL_USE_SSL = True
EMAIL_HOST = 'smtp.qq.com' # 如果是 163 改成 smtp.163.com
EMAIL_PORT = 465
EMAIL_HOST_USER = environ.get("EMAIL_SENDER") # 帐号
EMAIL_HOST_PASSWORD = environ.get("EMAIL_PWD") # 授权码(****)
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
注意:邮箱要开启smtp服务 并且记录授权码
https://docs.djangoproject.com/zh-hans/2.0/topics/email/
修改setting.py 加入邮箱配置
EMAIL_USE_SSL = True
EMAIL_HOST = 'smtp.qq.com' # 如果是 163 改成 smtp.163.com
EMAIL_PORT = 465
EMAIL_HOST_USER = "xxx@qq.com" # 帐号
EMAIL_HOST_PASSWORD = "xxxxx" # 授权码(****)
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
views里使用
普通单封邮件
def send_my_mail(req):
title = "阿里offer"
message = "恭喜您 成为我们公司CEO"
email_from = "1623@qq.com"
#收件者
recs = ["17625@163.com", "5684@qq.com", "ichi@163.com"]
#发送邮件
send_mail(title, message, email_from, recs)
return HttpResponse("CEO开始嗨起来")
多封普通邮件的发送
def send_emailss(req):
title1 = "腾讯offer"
message1 = "恭喜您 被骗了"
email_from = "16623@qq.com"
title2 = "这是一封挑事的邮件"
message2 = "大哥大哥别杀我"
recs1 = ["171425@163.com",
"5684@qq.com",
"ichzhi@163.com"]
recs2 = ["176425@163.com",
"56984@qq.com",
"ichezhi@163.com",
"m1100@163.com"]
senders1 = (title1, message1, email_from, recs1)
senders2 = (title2, message2, email_from, recs2)
send_mass_mail((senders1, senders2), fail_silently=False)
return HttpResponse("OK")
send_mail和send_mass_mail的区别
send_mail每次都连接SMTP服务
send_mass_mail 连一次就可以发多个
发送html的邮件
def email_html(req):
title = "阿里offer"
message = "恭喜您 成为我们公司CEO"
email_from = "49318@qq.com"
recs = [
"liaaaaaaaa@163.com",
]
html_content = '<a href={url}>{url}</a>'.format(url=url)
msg = EmailMultiAlternatives(title,message, email_from, recs)
msg.attach_alternative(html_content, "text/html")
msg.send()
return HttpResponse("OK")
邮箱验证码
1 生成验证码
2 准备邮件内容 拼接验证url
3 发送邮件
4 拿到url里的那个token
5 改变邮箱对应用户的状态
生成验证连接发送邮件
from django.core.mail import send_mail
from django.http import HttpResponse
from django.shortcuts import render
from email_verfiry import myutil
from django.core.cache import cache
# Create your views here.
def get_verify_code(req):
param = req.GET
email = param.get('email')
name = param.get('name')
#验证邮箱书写规则合法性
#验证这个邮箱是否在我们的系统注册过了
#生成验证码
token = myutil.get_token()
#拼接验证连接
verify_url = "https://www.baidu.com//verify/" + token
# 保存验证码
cache.set(token, email, 60)
# 发送邮件
title = "欢迎注册会员"
message = "请将如下连接 复制到浏览器访问{url}".format(
url=verify_url
)
email_from = "498@qq.com"
send_mail(title, message, email_from, [email])
return HttpResponse("注册成功,请查看激活邮件")
验证url的正确性
def verify(req, token):
email = cache.get(token)
if email:
# 去数据库找Email对应人
return HttpResponse("修改用户状态,可以使用"+email)
else:
return HttpResponse("验证链接不正确")