Ticket #510: csrf-protection2.patch
File csrf-protection2.patch, 7.5 KB (added by , 19 years ago) |
---|
-
models/auth.py
222 222 def _module_log_action(user_id, content_type_id, object_id, object_repr, action_flag, change_message=''): 223 223 e = LogEntry(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message) 224 224 e.save() 225 226 class CsrfToken(meta.Model): 227 token = meta.CharField(maxlength=200) 228 issued = meta.DateTimeField(auto_now=True) 229 user = meta.ForeignKey(User) 230 class META: 231 module_name = 'csrf' 232 verbose_name_plural = 'CSRF tokens' 233 db_table = 'auth_csrf_tokens' 234 ordering = ('-issued',) 235 236 def __repr__(self): 237 return self.token 238 239 def _module_create_token(user_id): 240 import md5, random 241 token = md5.new(str(random.random())).hexdigest() 242 ct = CsrfToken(None, token, 243 datetime.datetime.now(), user_id) 244 ct.save() 245 return ct 246 247 def _module_check_token(token, user_id): 248 try: 249 token = get_object(token__exact = token, 250 select = {'user_id': user_id}) 251 except CsrfTokenDoesNotExist: 252 return False 253 token.delete() 254 return True -
conf/admin_templates/delete_confirmation_generic.html
2 2 3 3 {% block content %} 4 4 5 {% if csrf_failed %}<p class="errornote">CSRF protection: Please re-submit.</p>{% endif %} 6 5 7 {% if perms_lacking %} 6 8 <p>Deleting the {{ object_name }} "{{ object }}" would result in deleting related objects, but your account doesn't have permission to delete the following types of objects:</p> 7 9 <ul> … … 15 17 <form action="" method="post"> 16 18 <input type="hidden" name="post" value="yes" /> 17 19 <input type="submit" value="Yes, I'm sure" /> 20 {% load csrf %}{% csrf_token %} 18 21 </form> 19 22 {% endif %} 20 23 -
templatetags/csrf.py
1 from django.core import template 2 from django.models.auth import csrf 3 import random, md5, datetime 4 5 class CsrfTokenNode(template.Node): 6 def render(self, context): 7 token = csrf.create_token(context['user'].id) 8 return '<input type="hidden" name="csrf_token" value="%s">' % token.token 9 10 def csrf_token(parser, token): 11 """ 12 {% csrf_token %} 13 """ 14 return CsrfTokenNode() 15 16 template.register_tag('csrf_token', csrf_token) -
views/admin/main.py
3 3 from django.core import formfields, meta, template_loader 4 4 from django.core.exceptions import Http404, ObjectDoesNotExist, PermissionDenied 5 5 from django.core.extensions import DjangoContext as Context 6 from django.models.auth import log 6 from django.models.auth import log, csrf 7 7 from django.utils.html import strip_tags 8 8 from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect 9 9 from django.utils.text import capfirst, get_text_list … … 588 588 if opts.admin.save_on_top: 589 589 t.extend(_get_submit_row_template(opts, app_label, add, change, show_delete, ordered_objects)) 590 590 t.append('{% if form.error_dict %}<p class="errornote">Please correct the error{{ form.error_dict.items|pluralize }} below.</p>{% endif %}\n') 591 t.append('{% if csrf_failed %}<p class="errornote">CSRF protection: Please re-submit.</p>{% endif %}\n') 591 592 for fieldset_name, options in admin_field_objs: 592 593 t.append('<fieldset class="module aligned %s">\n\n' % options.get('classes', '')) 593 594 if fieldset_name: … … 687 688 t.append('<li id="p{%% firstof %(x)s %%}"><span id="handlep{%% firstof %(x)s %%}">{{ object|truncatewords:"5" }}</span></li>' % \ 688 689 {'x': ' '.join(['object.%s' % o.pk.name for o in ordered_objects])}) 689 690 t.append('{% endfor %}</ul>{% endif %}\n') 691 t.append('{% load csrf %}{% csrf_token %}\n') 690 692 t.append('</form>\n</div>\n{% endblock %}') 691 693 return ''.join(t) 692 694 … … 764 766 if not request.user.has_perm(app_label + '.' + opts.get_add_permission()): 765 767 raise PermissionDenied 766 768 manipulator = mod.AddManipulator() 769 csrf_failed = False 767 770 if request.POST: 768 771 new_data = request.POST.copy() 769 772 if opts.has_field_type(meta.FileField): 770 773 new_data.update(request.FILES) 771 774 errors = manipulator.get_validation_errors(new_data) 772 if not errors and not request.POST.has_key("_preview"): 775 # Check the csrf_token 776 csrf_failed = not csrf.check_token(request.POST.get('csrf_token', ''), request.user.id) 777 if not errors and not csrf_failed and not request.POST.has_key("_preview"): 773 778 for f in opts.many_to_many: 774 779 if f.rel.raw_id_admin: 775 780 new_data.setlist(f.name, new_data[f.name].split(",")) … … 844 849 'title': 'Add %s' % opts.verbose_name, 845 850 "form": form, 846 851 "is_popup": request.REQUEST.has_key("_popup"), 852 "csrf_failed": csrf_failed, 847 853 }) 848 854 if object_id_override is not None: 849 855 c['object_id'] = object_id_override … … 864 870 raise Http404 865 871 866 872 inline_related_objects = opts.get_inline_related_objects() 873 csrf_failed = False 867 874 if request.POST: 868 875 new_data = request.POST.copy() 869 876 if opts.has_field_type(meta.FileField): 870 877 new_data.update(request.FILES) 871 878 872 879 errors = manipulator.get_validation_errors(new_data) 873 if not errors and not request.POST.has_key("_preview"): 880 # Check the csrf_token 881 csrf_failed = not csrf.check_token(request.POST.get('csrf_token', ''), request.user.id) 882 if not errors and not csrf_failed and not request.POST.has_key("_preview"): 874 883 for f in opts.many_to_many: 875 884 if f.rel.raw_id_admin: 876 885 new_data.setlist(f.name, new_data[f.name].split(",")) … … 969 978 "form": form, 970 979 'object_id': object_id, 971 980 'original': manipulator.original_object, 972 'is_popup' : request.REQUEST.has_key('_popup'), 981 'is_popup': request.REQUEST.has_key('_popup'), 982 'csrf_failed': csrf_failed, 973 983 }) 974 984 raw_template = _get_template(opts, app_label, change=True) 975 985 # return HttpResponse(raw_template, mimetype='text/plain') … … 1073 1083 deleted_objects = ['%s: <a href="../../%s/">%s</a>' % (capfirst(opts.verbose_name), object_id, strip_tags(repr(obj))), []] 1074 1084 perms_needed = sets.Set() 1075 1085 _get_deleted_objects(deleted_objects, perms_needed, request.user, obj, opts, 1) 1076 1077 if request.POST: # The user has already confirmed the deletion. 1086 csrf_failed = False 1087 if request.POST: 1088 csrf_failed = not csrf.check_token(request.POST.get('csrf_token', ''), request.user.id) 1089 if request.POST and not csrf_failed: # The user has already confirmed the deletion. 1078 1090 if perms_needed: 1079 1091 raise PermissionDenied 1080 1092 obj_repr = repr(obj) … … 1089 1101 "object": obj, 1090 1102 "deleted_objects": deleted_objects, 1091 1103 "perms_lacking": perms_needed, 1104 "csrf_failed": csrf_failed, 1092 1105 }) 1093 1106 return HttpResponse(t.render(c), mimetype='text/html; charset=utf-8') 1094 1107