#14976: Add is_html flag to contrib.messages
-----------------------------------+----------------------------------------
          Reporter:  tedtieken     |         Owner:  nobody              
            Status:  new           |     Milestone:                      
         Component:  Contrib apps  |       Version:  1.2                 
        Resolution:                |      Keywords:  safe, messages, html
             Stage:  Accepted      |     Has_patch:  0                   
        Needs_docs:  0             |   Needs_tests:  0                   
Needs_better_patch:  0             |  
-----------------------------------+----------------------------------------
Changes (by tedtieken):

  * keywords:  safe, messages => safe, messages, html

Comment:

 Not sure where "test" came from... probably end of the day brain fog.

 Agree with the change to "is_html"

 '''Cookie backend.'''  [[BR]]
 The current method stores the message as a 3 or 4 item list in json:
 [flag, level, message, ''optionally extra_tags'']. The decoding method
 relies on this information being a list of 3 or 4 items to recreate the
 message object:
 {{{
 #obj is the json object transformed into a list, obj[0] is a flag set to
 '__json_message'
 return Message(*obj[1:])
 }}}
 Adding another optional argument creates a problem.  If we have [flag,
 level, message, extra_tags, is_html] the message decoding works, but if we
 have [flag, level, message, is_html] then the is_html tag is positionally
 interpreted as the value of extra_tags.

 The solution I see to this is always store ''extra_tags'' and optionally
 store ''is_html.''  In the case where there aren't extra tags, store an
 empty string.
 {{{

 class MessageEncoder(json.JSONEncoder):
     """
     Compactly serializes instances of the ``Message`` class as JSON.
     """
     message_key = '__json_message'
     def default(self, obj):
         if isinstance(obj, Message):
             message = [self.message_key, obj.level, obj.message]
             if obj.extra_tags:
                 message.append(obj.extra_tags)
             else:                                    #New
                 message.append(str())                #New
             if obj.is_html:                          #New
                 message.append(obj.is_html)          #New
             return message
         return super(MessageEncoder, self).default(obj)
 }}}

 In the no extra_tags scenario, this solution has additional storage
 overhead of 4 characters - ,"", - IMHO that's acceptable.

 Legacy cookies will continue to pass the hash check because we haven't
 changed the hashing algorithm or what was stored.
 Since legacy messages are lists of length 3 or 4 and will never have the
 is_html flag set to true, the Message() call would still behave as
 expected with legacy cookies - the call would be either Message(level,
 message) or Message(level, message, extra_tags).

 '''XSS'''
 To use cookie stored messages in an xss attack, the attacker would have to
 know the site's secret key, because if the hash doesn't match the cookie
 backend discards the messages.

 Putting user input into an un-escaped output always has the possibility to
 open up an xss hole, but no more here than in any other feature.  By
 having is_html as an optional, False-by-default variable I think we make
 it pretty hard to accidentally display a message as html.


 Going to take a look at the session backend tonight.

-- 
Ticket URL: <http://code.djangoproject.com/ticket/14976#comment:3>
Django <http://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to