Permalink
Browse files

Merge pull request #1 from sirdarckcat/sirdarckcat-cspnonces

Adding CSP nonces support and introducing an XSS
  • Loading branch information...
sirdarckcat committed Dec 27, 2016
2 parents b4c0299 + 3ff90cb commit fc5161df0a6b778471bde879bbc44cb8a9eade59
Showing with 75 additions and 23 deletions.
  1. +5 −0 app.yaml
  2. +5 −0 appengine_config.py
  3. +4 −0 cron.yaml
  4. +26 −7 guestbook.py
  5. +34 −16 index.html
  6. +1 −0 lib/README.md
View
@@ -11,8 +11,13 @@ handlers:
- url: /bootstrap
static_dir: bootstrap
- url: /tasks/.*
script: guestbook.app
login: admin
- url: /.*
script: guestbook.app
# [END handlers]
# [START libraries]
View
@@ -0,0 +1,5 @@
# appengine_config.py
from google.appengine.ext import vendor
# Add any libraries install in the "lib" folder.
vendor.add('lib')
View
@@ -0,0 +1,4 @@
cron:
- description: daily purge
url: /tasks/purge
schedule: every 24 hours
View
@@ -16,12 +16,14 @@
# [START imports]
import os
import random
import urllib
from google.appengine.api import users
from google.appengine.ext import ndb
import jinja2
import simplejson
import webapp2
JINJA_ENVIRONMENT = jinja2.Environment(
@@ -65,12 +67,10 @@ class Greeting(ndb.Model):
class MainPage(webapp2.RequestHandler):
def get(self):
random.seed(os.urandom(8))
nonce = ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for i in range(8))
guestbook_name = self.request.get('guestbook_name',
DEFAULT_GUESTBOOK_NAME)
greetings_query = Greeting.query(
ancestor=guestbook_key(guestbook_name)).order(-Greeting.date)
greetings = greetings_query.fetch(10)
user = users.get_current_user()
if user:
url = users.create_logout_url(self.request.uri)
@@ -81,19 +81,27 @@ def get(self):
template_values = {
'user': user,
'greetings': greetings,
'guestbook_name': urllib.quote_plus(guestbook_name),
'url': url,
'url_linktext': url_linktext,
'nonce': nonce,
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.headers.add("Content-Security-Policy","script-src 'nonce-%s'; object-src 'none'"%nonce)
self.response.write(template.render(template_values))
# [END main_page]
# [START guestbook]
class Guestbook(webapp2.RequestHandler):
def get(self):
guestbook_name = self.request.get('guestbook_name',
DEFAULT_GUESTBOOK_NAME)
greetings_query = Greeting.query(
ancestor=guestbook_key(guestbook_name)).order(-Greeting.date)
greetings = greetings_query.fetch(10)
self.response.write(simplejson.dumps(list({"content": g.content} for g in greetings),
cls=simplejson.encoder.JSONEncoderForHTML))
def post(self):
# We set the same parent key on the 'Greeting' to ensure each
@@ -118,9 +126,20 @@ def post(self):
# [END guestbook]
# [START purge]
class Purge(webapp2.RequestHandler):
def post(self):
greetings_query = Greeting.query().fetch(1000, keys_only=True)
ndb.delete_multi(list(greetings_query))
# [END purge]
# [START app]
app = webapp2.WSGIApplication([
('/', MainPage),
('/sign', Guestbook),
('/guestbook', Guestbook),
# Tasks
('/tasks/purge', Purge),
], debug=True)
# [END app]
View
@@ -50,36 +50,54 @@
</div>
<div class="container">
<!-- [START greetings] -->
{% for greeting in greetings %}
<div class="row">
{% if greeting.author %}
<b>{{ greeting.author.email }}
{% if user and user.user_id() == greeting.author.identity %}
(You)
{% endif %}
</b> wrote:
{% else %}
An anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content }}</blockquote>
<div class="row" id="gbrow">
<blockquote></blockquote>
</div>
{% endfor %}
<!-- [END greetings] -->
<form action="/sign?guestbook_name={{ guestbook_name }}" method="post">
<form action="guestbook" method="post" id="gbsubmit">
<input value="{{ guestbook_name }}" name="guestbook_name" type="hidden">
<div><textarea name="content" class="input-block-level" rows="3"></textarea></div>
<div><input type="submit" class="btn btn-large btn-primary" value="Sign Guestbook"></div>
</form>
<hr>
<form>Guestbook name:
<input value="{{ guestbook_name }}" name="guestbook_name">
<form id="gbform">Guestbook name:
<input value="{{ guestbook_name }}" name="guestbook_name" id="gbname">
<input type="submit" value="switch">
</form>
<a href="{{ url|safe }}">{{ url_linktext }}</a>
</div>
<script nonce="{{ nonce }}">
var submit = document.getElementById("gbsubmit");
var name = document.getElementById("gbname");
var form = document.getElementById("gbform");
var row = document.getElementById("gbrow");
var rows = [];
var table = row.parentNode;
function updateGuestbook() {
var url = "?guestbook_name="+encodeURIComponent(gbname.value);
submit.elements.guestbook_name.value = gbname.value;
history.pushState(null, "", url);
// Remove old rows.
rows.forEach(r=>r.parentNode.removeChild(r));
rows=[];
fetch("/guestbook" + url, {credentials: "include"}).then(r=>r.json()).then(j=>{
j.forEach(m=>{
var elem = table.insertBefore(row.cloneNode(true), table.firstChild);
rows.push(elem);
// Note this is an XSS.
elem.getElementsByTagName("blockquote")[0].innerHTML=m.content;
});
}).catch(e=>{
alert("Error loading guestbook comments");
});
return false;
}
gbform.onsubmit = window.onload = updateGuestbook;
</script>
</body>
</html>
{% endautoescape %}
View
@@ -0,0 +1 @@
please run `pip install -t . simplejson` on this directory.

0 comments on commit fc5161d

Please sign in to comment.