Ticket #4049: trac-csrf.3.patch
| File trac-csrf.3.patch, 2.9 KB (added by jonas, 2 years ago) |
|---|
-
trac/web/chrome.py
432 432 'href': req and req.href, 433 433 'perm': req and req.perm, 434 434 'authname': req and req.authname or '<trac>', 435 'form_token': req.form_token, 435 436 436 437 # Date/time formatting 437 438 'format_datetime': partial(format_datetime, tzinfo=tzinfo), -
trac/web/main.py
173 173 'hdf': self._get_hdf, 174 174 'perm': self._get_perm, 175 175 'session': self._get_session, 176 'tz': self._get_timezone 176 'tz': self._get_timezone, 177 'form_token': self._get_form_token 177 178 }) 178 179 179 180 # Select the component that should handle the request … … 193 194 req.callbacks['chrome'] = partial(chrome.prepare_request, 194 195 handler=chosen_handler) 195 196 197 # Protect against CSRF attacks. 198 # We can only block against suck attacks if the user is logged in 199 # or if we have an incoming session cookie. 200 if (req.method == 'POST' and 201 req.args.get('__FORM_TOKEN') != req.form_token and 202 (req.incookie.has_key('trac_auth') or 203 req.incookie.has_key('trac_session'))): 204 raise TracError('Missing or invalid form token') 205 196 206 # Process the request and render the template 197 207 try: 198 208 try: … … 251 261 except: 252 262 return localtz 253 263 264 def _get_form_token(self, req): 265 """Used to protect against CSRF. 266 267 The 'trac_auth' cookie is a good and strong shared secret, only 268 known by the user it belongs to and Trac itself. 269 270 The session id is our second best option, not as reliable since 271 it will change on each request if the user has cookies disabled in 272 his/her browser. 273 """ 274 if req.incookie.has_key('trac_auth'): 275 return req.incookie['trac_auth'].value 276 else: 277 return req.session.sid 278 254 279 def _pre_process_request(self, req, chosen_handler): 255 280 for filter_ in self.filters: 256 281 chosen_handler = filter_.pre_process_request(req, chosen_handler) -
templates/layout.html
80 80 </div> 81 81 </body> 82 82 83 <form py:match="form[@method='post' and @avoidloop!='true']" 84 avoidloop="true" py:attrs="select('@*')"> 85 <input type="hidden" name="__FORM_TOKEN" value="$form_token"/> 86 ${select('*|text()')} 87 </form> 88 83 89 <xi:include href="site.html"><xi:fallback /></xi:include> 84 90 85 91 </html>
