Ticket #4049: trac-0.10-csrf.3.patch
| File trac-0.10-csrf.3.patch, 5.1 KB (added by jonas, 5 years ago) |
|---|
-
trac/web/api.py
127 127 authname = None 128 128 perm = None 129 129 session = None 130 form_token = None 130 131 131 132 def __init__(self, environ, start_response): 132 133 """Create the request wrapper. … … 350 351 content_type = 'text/plain' 351 352 data = str(self.hdf) 352 353 else: 353 data = self.hdf.render(template )354 data = self.hdf.render(template, self.form_token) 354 355 355 356 self.send_response(status) 356 357 self.send_header('Cache-control', 'must-revalidate') -
trac/web/clearsilver.py
14 14 # 15 15 # Author: Christopher Lenz <cmlenz@gmx.de> 16 16 17 from HTMLParser import HTMLParser 18 17 19 from trac.core import TracError 18 20 from trac.util.html import Markup, Fragment, escape 19 21 from trac.util.text import to_unicode … … 274 276 cs.parseStr(string) 275 277 return cs 276 278 277 def render(self, template ):279 def render(self, template, form_token=None): 278 280 """Render the HDF using the given template. 279 281 280 282 The template parameter can be either an already parse neo_cs.CS … … 286 288 import neo_cs 287 289 template = neo_cs.CS(self.hdf) 288 290 template.parseFile(filename) 289 return template.render()290 291 292 if form_token: 293 from cStringIO import StringIO 294 out = StringIO() 295 injector = FormTokenInjector(form_token, out) 296 injector.feed(template.render()) 297 return out.getvalue() 298 else: 299 return template.render() 291 300 301 302 class FormTokenInjector(HTMLParser): 303 """Identify and protect forms from CSRF attacks 304 305 This filter works by adding a input type=hidden field to POST forms. 306 """ 307 def __init__(self, form_token, out): 308 HTMLParser.__init__(self) 309 self.out = out 310 self.token = form_token 311 312 def handle_starttag(self, tag, attrs): 313 self.out.write(self.get_starttag_text()) 314 if tag.lower() == 'form': 315 for name, value in attrs: 316 if name.lower() == 'method' and value.lower() == 'post': 317 self.out.write('<input type="hidden" name="__FORM_TOKEN"' 318 ' value="%s"/>' % self.token) 319 break 320 321 def handle_startendtag(self, tag, attrs): 322 self.out.write(self.get_starttag_text()) 323 324 def handle_charref(self, name): 325 self.out.write('&#%s;' % name) 326 327 def handle_entityref(self, name): 328 self.out.write('&%s;' % name) 329 330 def handle_comment(self, data): 331 self.out.write('<!--%s-->' % data) 332 333 def handle_decl(self, data): 334 self.out.write('<!%s>' % data) 335 336 def handle_pi(self, data): 337 self.out.write('<?%s?>' % data) 338 339 def handle_data(self, data): 340 self.out.write(data) 341 342 def handle_endtag(self, tag): 343 self.out.write('</' + tag + '>') 344 345 292 346 if __name__ == '__main__': 293 347 import doctest, sys 294 348 doctest.testmod(sys.modules[__name__]) -
trac/web/main.py
189 189 req.authname = self.authenticate(req) 190 190 req.perm = PermissionCache(self.env, req.authname) 191 191 req.session = Session(self.env, req) 192 req.form_token = self._get_form_token(req) 192 193 except: 193 194 anonymous_request = True 194 195 early_error = sys.exc_info() … … 221 222 try: 222 223 try: 223 224 try: 225 # Protect against CSRF attacks. 226 if (req.method == 'POST' and 227 req.args.get('__FORM_TOKEN') != req.form_token): 228 raise TracError('Missing or invalid form token ' 229 'Do you have cookies enabled?') 230 224 231 resp = chosen_handler.process_request(req) 225 232 if resp: 226 233 template, content_type = \ … … 257 264 content_type) 258 265 return template, content_type 259 266 267 def _get_form_token(self, req): 268 """Used to protect against CSRF. 260 269 270 The 'trac_auth' cookie is a good and strong shared secret, only 271 known by the user it belongs to and Trac itself. 272 273 The session id is our second best option, not as reliable since 274 it will change on each request if the user has cookies disabled in 275 his/her browser. 276 """ 277 if req.incookie.has_key('trac_auth'): 278 return req.incookie['trac_auth'].value 279 else: 280 return req.session.sid 281 282 261 283 def dispatch_request(environ, start_response): 262 284 """Main entry point for the Trac web interface. 263 285
