Django i18n External Redirect security issue - django

(I'm new with Django)
I ran an automated scan (OWASP ZAP) to test my application security and it's returning a high risk flag for External Redirect:
Automated Scan Alert
Looks like it's something to do with the path "/i18n/setlang/" and the parameter "next", like "?next=(redirect)"
I set the i18n path like that
urlpatterns = [ path('i18n/', include('django.conf.urls.i18n')), ... ]
And this is my HTML
<div class="flex justify-items-end">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<form action="{% url 'set_language' %}" method="post" id="form_{{ language.code }}" style="display:inline!important;">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<input name="language" type="hidden" value="{{ language.code }}" />
</form>
<button class="lang-button" type="submit" form="form_{{ language.code }}" value="Submit">
{% if language.code == "en" %}
<img src="{% static 'assets/webfonts/gb.svg' %}" width="30" alt="gb" class="rounded-lg h-5 w-5 mr-3 hover:opacity-75" />
{% endif %}
{% if language.code == "es" %}
<img src="{% static 'assets/webfonts/es.svg' %}" width="30" alt="gb" class="rounded-lg h-5 w-5 hover:opacity-75" />
{% endif %}
{% if language.code == "pt" %}
<img src="{% static 'assets/webfonts/br.svg' %}" width="30" alt="gb" class="rounded-lg h-5 w-5 mr-3 hover:opacity-75" />
{% endif %}
</button>
{% endfor %}
</div>
I don't know if it's really a security issue because it says at the end of the report description that "URL redirectors do not necessarily represent a direct security vulnerability but can be abused by attackers trying to social engineer victims into believing that they are navigating to a site other than the true destination"
What should I do? :(

Although you haven't provided enough specific to be 100% sure my educated guess would be that you aren't validating/restricting the value of next at all. So when ZAP set next=SomeRandomNumber.owasp.org your app accepted it and the user is subsequently redirected to https://SomeRandomNumber.owasp.org

Related

Django Allauth Customized Login Template Not Working

I have customized the login template of allauth with bootstrap styles and widget_tweaks. When I try logging in with that template, It doesn't redirect me to the home page but remains in the same login.html template. However, when I log in with the original template from allauth in /account/login.html/ everything works well and it redirects me to my homepage. There is something that I'm not customizing right in my custom login.html template.
Below is django-allauth login.html and my custom login.html
django-allauth login.html
{% extends "account/base.html" %}
{% load i18n %}
{% load account socialaccount %}
{% block head_title %}{% trans "Sign In" %}{% endblock %}
{% block content %}
<h1>{% trans "Sign In" %}</h1>
{% get_providers as socialaccount_providers %}
{% if socialaccount_providers %}
<p>{% blocktrans with site.name as site_name %}Please sign in with one
of your existing third party accounts. Or, sign up
for a {{ site_name }} account and sign in below:{% endblocktrans %}</p>
<div class="socialaccount_ballot">
<ul class="socialaccount_providers">
{% include "socialaccount/snippets/provider_list.html" with process="login" %}
</ul>
<div class="login-or">{% trans 'or' %}</div>
</div>
{% include "socialaccount/snippets/login_extra.html" %}
{% else %}
<p>{% blocktrans %}If you have not created an account yet, then please
sign up first.{% endblocktrans %}</p>
{% endif %}
<form class="login" method="POST" action="{% url 'account_login' %}">
{% csrf_token %}
{{ form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<a class="button secondaryAction" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
<button class="primaryAction" type="submit">{% trans "Sign In" %}</button>
</form>
{% endblock %}
my custom login.html
{% comment %}
{% extends "layouts/base-fullscreen.html" %}
{% load i18n %}
{% block title %} Login {% endblock %}
{% load widget_tweaks %}
{% block content %}
<div class="auth-wrapper">
<div class="auth-content">
<div class="auth-bg">
<span class="r"></span>
<span class="r s"></span>
<span class="r s"></span>
<span class="r"></span>
</div>
<div class="card">
<div class="card-body text-center">
<div class="mb-4">
<i class="feather icon-unlock auth-icon"></i>
</div>
<h3 class="mb-4">Login</h3>
<span class="mb-0 text-muted">
{% if msg %}
{{ msg | safe }}
{% else %}
Add your credentials
{% endif %}
</span>
<br />
<br />
<form method="post" action="{% url 'account_login' %}">
{% csrf_token %}
<div class="md-form mb-2">
{% render_field form.login class="form-control" placeholder=form.login.label %}
</div>
<span class="text-error">{{ form.login.errors }}</span>
<div class="md-form mb-2">
{% render_field form.password class="form-control" placeholder=form.password.label %}
</div>
<span class="text-error">{{ form.password.errors }}</span>
<p class="mb-0 text-muted"><a class="button secondaryAction" href="{% url 'account_reset_password' %}">Forgot password?</a>
</p>
<div class="form-group text-left">
<div class="checkbox checkbox-fill d-inline">
<!-- <input type="checkbox" name="checkbox-fill-1" id="checkbox-fill-a1" checked=""> -->
{% render_field form.remember class="form-control" placeholder=form.remember.label type="checkbox"%}
<label for="id_remember" class="cr"> Remember me</label>
</div>
</div>
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit" name="login" class="btn btn-primary shadow-2 mb-4">Login</button>
</form>
<p class="mb-0 text-muted">Don’t have an account? <a href="{% url 'account_signup' %}" >Signup</a></p>
<br />
</div>
</div>
</div>
</div>
{% endblock content %}
allauth settings in settings.py
LOGIN_REDIRECT_URL = '/'
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_ID = 1
ACCOUNT_LOGOUT_REDIRECT_URL = '/' #couterpart to Django's LOGIN_REDIRECT_URL
ACCOUNT_LOGOUT_REDIRECT = '/'
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_EMAIL_VERIFICATION = 'optional'
The other change I've made is to customize the allauth signup form to take extra two fields (first_name and last_name). That one works fine and redirects to the login url
you might be getting an error from the form validator. keep the original form on the page to check if its giving any errors. copy the {{ form.as_p }} from the original page 'accounts/login.html' and paste it in your custom template. if there are any errors, it'll display it.
this right here is your problem
{% extends "account/base.html" %}
If you have all the boostrap, jquery and widget_tweaks in your local base.html, then thats what you need to extend. The default accounts/base.html provided by django-allauth, does not come customized with bootstrap.
Use:
{% extends "base.html" %} instead

Django 2 versions of german

I'm developing website with 2 versions of german (Default and Austrian).
My problem is that template do not differ them, so in select django displays them both as Deutsch(de).
Languages in settings.py:
('en', _('English')),
('de', _('German')),
('de-at', _('Austrian'))
template code:
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select style="border:1px dotted black" name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input class="btn-primary" type="submit" value="{% trans 'Change' %}" />
</form>
Code is from documentation.
Translation in Austrian language doesn't work, because django in select defines Austrian as default Deutsch select it and do not translate.
So, are there any ways to display sublanguage in template, like (Deutsch(de-at)) or just (Austrian instead of Deutsch), or are there any other ways to solve it?
Tried to change all languages in settings:
('en-us', _('English')),
('de-de', _('German')),
('de-at', _('Austrian'))
Then created .po and .mo files to them. But still template defines them as same languages. Also I thought about changing language name in template, but as far as I understand I can't do it.
I've sold my problem, still don't understand what's the reason...
Django front end form, that I copied from documentation doesn't work as it should.
Form, that I used on front side works correct only with base languages and crashes on sublanguages(all). Now I've rewrite this form:
<form action="/i18n/setlang/" method="post">
{% csrf_token %}
<select style="border:1px solid black" name="language">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}"
{% ifequal lang.0 request.LANGUAGE_CODE %}
selected="yes"
{% endifequal %}
>{{ lang.1 }}</option>
{% endfor %}
</select>
<input type="submit" value="{% trans 'Change' %}" />
</form>
Per now it works fine...

Django i18n explorer verification failed

I am using the below code in my site wide template...
{% for lang in languages %}
<li>
<form name="setLang{{ lang.1}}" action="/i18n/setlang/" method="POST">{% csrf_token %}
<input name="next" type="hidden" value="/" />
<input type="hidden" name="language" value="{{ lang.0 }}" />
<a class='{% if LANGUAGE_CODE == lang.0 %}selected{% endif %}' href="#" onclick="document.setLang{{ lang.1 }}.submit();return false;">{{ lang.0 }}</a>
</form>
</li>
{% endfor %}
and in urls.py i have
(r'^i18n/', include('django.conf.urls.i18n'))
But on internet explorer i am getting csrf verification failed error... Is the problem about there are two forms on the page?
Well I'm not sure if this will solve your problem, but you should definitely put a space after {{ lang.1 so that it looks like {{ lang.1 }}. It is worth trying that, at least, to see if the semantics is causing a break somewhere.

invalid block-tag when I implement i18n

I'm currently adding i18n in my website but there is something wrong.
When I use code from djangoproject
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}">{{ language.name_local }} ({{ language.code }})</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
I get this error
Invalid block tag: 'get_language_info_list'
I don't understand why get_language_info_list is unknown. Templates_context_processors is ok. HTML form is on my homepage.
Always make sure you load the tag library first before you requests any tags. To use get_language_info_list, you need to make sure {% load i18n %} is in your template.

Django comments flag "cancel" returns wrong url

I've set up django's built in comments in my application and I'm employing the flagging ability. The flagging works fine, but the 'cancel" link that appears on the template returns the following error:
could not find http
The template/form is as follows:
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Flag this comment" %}{% endblock %}
{% block content %}
<h3>{% trans "Are you sure you want to flag this comment?" %}</h3>
<br />
<blockquote>{{ comment|linebreaks }}</blockquote>
<form action="." method="post">{% csrf_token %}
{% if next %}<div><input type="hidden" name="next" value="{{ next }}" id="next" /></div>{% endif %}
<p class="submit">
<input type="submit" class="btn btn-danger button-left" name="submit" value="{% trans "Flag" %}" /> or cancel
</p>
</form>
{% endblock %}
Any insight into this would be greatly appreciated.
I suspect it might be that you're site settings aren't correct. Check the sites app and see if you can make some changes there to get it working.