CSRF LOG 郵箱配置及使用
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 = "[email protected]" # 帳號
EMAIL_HOST_PASSWORD = "xxxxx" # 授權碼(****)
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
views裡使用
普通單封郵件
def send_my_mail(req):
title = "阿里offer"
message = "恭喜您 成為我們公司CEO"
email_from = "[email protected]"
#收件者
recs = ["[email protected]", "[email protected]", "[email protected]"]
#傳送郵件
send_mail(title, message, email_from, recs)
return HttpResponse("CEO開始嗨起來")
多封普通郵件的傳送
def send_emailss(req):
title1 = "騰訊offer"
message1 = "恭喜您 被騙了"
email_from = "[email protected]"
title2 = "這是一封挑事的郵件"
message2 = "大哥大哥別殺我"
recs1 = ["[email protected]",
"[email protected]",
"[email protected]"]
recs2 = ["[email protected]",
"[email protected]",
"[email protected]",
"[email protected]"]
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 = "[email protected]"
recs = [
"[email protected]",
]
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 = "[email protected]"
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("驗證連結不正確")