ã€Pyhon/Django】ãƒã‚°ã‚¤ãƒ³æ©Ÿèƒ½ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º
最近ã¯ã‚‚ã£ã±ã‚‰Djangoã§ã®ã‚µã‚¤ãƒˆæ§‹ç¯‰ã®æ„Ÿè§¦ã‚’探りãªãŒã‚‰é–‹ç™ºã—ã¦ã„ã¾ã™ï¼ˆèª¿ã¹ã‚‹æ™‚é–“ã®æ–¹ãŒåœ§å€’çš„ã«å¤šã„ã§ã™ãŒï¼‰ 当ブãƒã‚°ã§ã‚‚Djangoã§ã®æ©Ÿèƒ½è¿½åŠ ã‚„ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚ºã«ã¤ã„ã¦æŠ•ç¨¿ã—ã¦ãŠã‚Šã¾ã™ã€‚ ãã®ä¸ã§ã€å…ˆæ—¥ã®è¨˜äº‹ã€Pyhon/Django】カスタムユーザã¨ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ãƒã‚°ã‚¤ãƒ³ï¼‘ã«ã¤ã„㦠開発ã—ã¦ã„ã上ã§ä¿®æ£ãŒå¿…è¦ãªéƒ¨åˆ†ã‚りã¾ã—ãŸã®ã§ã€ã“ã¡ã‚‰ã«è¨˜è¼‰ã—ã¦ã„ãã¾ã™ã€‚
ä¿®æ£ãŒå¿…è¦ãªéƒ¨åˆ†
ãƒã‚°ã‚¤ãƒ³æ©Ÿèƒ½ã®ä¸ã§ãƒã‚°ã‚¤ãƒ³å¾Œã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆå…ˆã‚’指定ã—ã¦ã„ã‚‹ã®ã§ã™ãŒ パスを固定値ã«ã—ã¦ã„ã‚‹ãŸã‚ã«ãƒã‚°ã‚¤ãƒ³ãŒå¿…è¦ãªé ˜åŸŸã«ã‚¢ã‚¯ã‚»ã‚¹ã—ãŸéš›ã« 『ãƒã‚°ã‚¤ãƒ³ç”»é¢â‡’å…ƒã®ãƒšãƒ¼ã‚¸ã«æˆ»ã‚‹ã€ã¨ã„ã†åˆ¶å¾¡ãŒã§ãã¾ã›ã‚“。 ã‹ã£ã“悪ã„ã®ã§ä¿®æ£ã—ã¾ã™ã€‚
å‰å›žã®ã‚³ãƒ¼ãƒ‰ãŠã•らã„
対象ã¨ãªã‚‹ã®ã¯views.py部分ã«ãªã‚Šã¾ã™ã€‚ ãƒã‚°ã‚¤ãƒ³å‡¦ç†ã®è©²å½“部分ã®ã¿æŠœç²‹ã—ã¦ã„ã¾ã™ã€‚
class LoginView(View):
def post(self, request, *args, **kwargs):
template_name = 'login.html'
success = 'home'
form = LoginForm(data=request.POST)
if form.is_valid():
# フォームã‹ã‚‰'email'ã‚’èªã¿å–ã‚‹
email = form.cleaned_data.get('email')
# フォームã‹ã‚‰'password'ã‚’èªã¿å–ã‚‹
password = form.cleaned_data.get('password')
auth_object = EmailAuthBackend()
user = auth_object.authenticate(email=email, password=password)
if user is not None:
#èªè¨¼å‡¦ç†
login(request, user, backend='user.auth.EmailAuthBackend')
return redirect(success)
else:
return render(request, template_name, {'context': 'ãƒã‚°ã‚¤ãƒ³ã«å¤±æ•—ã—ã¾ã—ãŸ'})
def get(self, request, *args, **kwargs):
template_name = 'login.html'
form = LoginForm(request.POST)
return render(request, template_name, {'context': 'get'})
æˆåŠŸã—ãŸå ´åˆã«successã§æŒ‡å®šã—ãŸ"home"ã«å¿…ãšãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã—ã¦ã„ã‚‹ãŸã‚ 元々アクセスã—よã†ã¨ã—ã¦ã„ãŸURLã®æƒ…å ±ãŒãªããªã£ã¦ã—ã¾ã£ã¦ã„ã¾ã™ã€‚
ä¿®æ£å¾Œã®ã‚½ãƒ¼ã‚¹
views.pyã¨login.htmlã®ï¼’ã¤ã®ãƒ•ァイルを修æ£ã—ã¾ã™ã€‚ ã¾ã™ã¯views.py
class LoginView(View):
def post(self, request, *args, **kwargs):
template_name = 'login.html'
success = 'home'
form = LoginForm(data=request.POST)
if form.is_valid():
# フォームã‹ã‚‰'email'ã‚’èªã¿å–ã‚‹
email = form.cleaned_data.get('email')
# フォームã‹ã‚‰'password'ã‚’èªã¿å–ã‚‹
password = form.cleaned_data.get('password')
auth_object = EmailAuthBackend()
user = auth_object.authenticate(email=email, password=password)
if user is not None:
#èªè¨¼å‡¦ç†
login(request, user, backend='user.auth.EmailAuthBackend')
redirect_to = request.POST.get('redirect_to') #1 redirect_toã®å–å¾—
if redirect_to is not None:
return redirect(redirect_to)
else:
return redirect(success)
else:
return render(request, template_name, {'context': 'ãƒã‚°ã‚¤ãƒ³ã«å¤±æ•—ã—ã¾ã—ãŸ'})
def get(self, request, *args, **kwargs):
template_name = 'login.html'
form = LoginForm(request.POST)
redirect_to = request.GET.get('next') #2 getパラメータã§å—ã‘å–ã£ãŸnextã‚’templateã¸æ¸¡ã™
return render(request, template_name, {'context': 'get', 'redirect_to': redirect_to})
ã¾ãš#1ã®éƒ¨åˆ†ã§ã™ãŒã€postパラメータã§ãƒã‚°ã‚¤ãƒ³å¾Œã®é·ç§»å…ˆã‚’å—ã‘å–ã£ã¦ã„ã¾ã™ã€‚ ã‚‚ã—æŒ‡å®šã•れã¦ã„ãªã‘れã°ã€å…±é€šã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆå…ˆï¼ˆhome)ã«é·ç§»ã™ã‚‹ã‚ˆã†ã«ã—ã¾ã™ã€‚ パラメータをå—ã‘å–ã£ã¦ã„ã¾ã™ã®ã§ã€htmlã®formã‹ã‚‰ã€Œredirect_toã€ã¨ã„ã†å€¤ã‚’ 渡ã™å¿…è¦ãŒã‚りã¾ã™ã€‚ #2ã¯getパラメータã‹ã‚‰ã€Œnextã€ã¨ã„ã†å€¤ã‚’å–å¾—ã—ã¦ã„ã¾ã™ã€‚ 「nextã€ã¨ã„ã†ãƒ‘ラメータã¯Djangoã®èªè¨¼æ©Ÿèƒ½ã«çµ„ã¿è¾¼ã¾ã‚Œã¦ãŠã‚Š ãƒã‚°ã‚¤ãƒ³ãŒå¿…è¦ãªé ˜åŸŸã«ã‚¢ã‚¯ã‚»ã‚¹ã—ãŸéš›ã«getパラメータã«å‹æ‰‹ã«ã€Œnextã€ã¨ã„ã†ãƒ‘ラメータå㧠アクセスã—よã†ã¨ã—ã¦ã„ãŸãƒ‘ã‚¹ãŒæ ¼ç´ã•れã¾ã™ã€‚ ã“ã®ã€Œnextã€ã®å€¤ã‚’å—ã‘å–りã€login.htmlã«æ¸¡ã—ã¾ã™ã€‚ ãれã§ã¯æ¬¡ã«login.htmlã®ä¿®æ£ã§ã™ã€‚
<body class="text-center">
<main class="form-signin">
<form method="post">{% csrf_token %}
<img class="mb-4" src="/docs/5.0/assets/brand/bootstrap-logo.svg" alt="Django" width="72" height="57">
<h1 class="h3 mb-3 fw-normal">ãƒã‚°ã‚¤ãƒ³</h1>
{{ context }}
<label for="inputEmail" class="visually-hidden">メールアドレス</label>
<input type="email" id="inputEmail" class="form-control" placeholder="メールアドレス" name = "email" required autofocus>
<label for="inputPassword" class="visually-hidden">パスワード</label>
<input type="password" id="inputPassword" class="form-control" placeholder="パスワード" name = "password" required>
{% if redirect_to is not None %} <!-#3-ä¿®æ£ç‚¹ã“ã“ã‹ã‚‰-->
<input type="hidden" name="redirect_to" value="{{ redirect_to }}">
{% endif %} <!-#3-ä¿®æ£ç‚¹ã“ã“ã¾ã§-->
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> 記憶ã™ã‚‹
</label>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit">ãƒã‚°ã‚¤ãƒ³</button>
<p class="mt-5 mb-3 text-muted">&amp;copy; 2017-2021</p>
</form>
</main>
</body>
ä¿®æ£ç‚¹ã¯11行目ã®è¿½åР飲ã¿ã§ã™ã€‚ views.pyã‹ã‚‰æ¸¡ã•れãŸã€Œredirect_to ã€ã®å€¤ã‚’hiddenã«åŸ‹ã‚込んã§ã€å†åº¦views.pyã«æ¸¡ã—ã¦ã‚„りã¾ã™ã€‚ ã“ã†ã™ã‚‹ã“ã¨ã§ã€ãƒã‚°ã‚¤ãƒ³ãŒæˆåŠŸã—ãŸå ´åˆã«å…ƒã€…アクセスã—よã†ã¨ã—ã¦ã„ãŸãƒšãƒ¼ã‚¸ã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
課題
ãƒã‚°ã‚¤ãƒ³å¾Œã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆå…ˆã¯getãƒ‘ãƒ©ãƒ¡ãƒ¼ã‚¿ã«æŒ‡å®šã—ãŸå€¤ã‚’利用ã—ã¦ã„ã¾ã™ã€‚ ãã®ãŸã‚ã€URLã‚’æ›¸ãæ›ãˆã‚‹ã“ã¨ã§
ãƒã‚°ã‚¤ãƒ³å¾Œã«ä»–ã®ã‚µã‚¤ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã•ã›ã‚‹ã“ã¨ã‚‚ã§ãã¦ã—ã¾ã„ã¾ã™ã€‚
ã“れを悪用ã•れるã¨ã€ä¾‹ãˆã°ä¸‹è¨˜ã®ã‚ˆã†ãªURLã‚’ã©ã“ã‹ã«æŽ²è¼‰ã•れã¦ã—ã¾ã†ã¨
ãƒã‚°ã‚¤ãƒ³å¾Œã«å‹æ‰‹ã«yahooトップã«é£›ã°ã™ã“ã¨ã‚‚ã§ãã¦ã—ã¾ã„ã¾ã™ã€‚
https://ドメイン/?next=https://yahoo.co.jp
é·ç§»å…ˆãŒyahooトップãªã‚‰ã¾ã ã„ã„ã®ã§ã™ãŒã€ã“ã®é·ç§»å…ˆã‚’フィッシングサイトã«ã—ã¦
悪用ã•れるã“ã¨ãŒã‚りã¾ã™ã€‚
ã“ã®ã‚ˆã†ãªã‚»ã‚ュリティ対ç–ã®ãŸã‚ã€ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆå…ˆã®URLをパラメータã‹ã‚‰å–å¾—ã—ã¦åˆ©ç”¨ã™ã‚‹å ´åˆã¯
ドメインをホワイトリストã¨ã—ã¦ç®¡ç†ã™ã‚‹ã‹ã€ç›¸å¯¾ãƒ‘スã—ã‹å—ã‘付ã‘ãªã„よã†ã«åˆ¶å¾¡ã‚’入れる必è¦ãŒã‚りã¾ã™ã€‚
Djangoãã®ä»–ã®è¨˜äº‹
ã€Pyhon/Django】ãƒã‚°ã‚¤ãƒ³æ©Ÿèƒ½ã‚«ã‚¹ã‚¿ãƒžã‚¤ã‚º
2021年7月12日
Python/Django éé‡ã—ãŸã‚¨ãƒ©ãƒ¼é›†ã¨è§£æ±ºæ–¹æ³•
2021年7月6日
Djangoã§adminã«ã‚«ã‚¹ã‚¿ãƒ フィルタ追åŠ
2021年6月19日




