Comment embeds: add per-comment token

While in the process of rolling out comment embeds, we'd like to have restrict
our beta a bit - because by their nature, once embeds are out, we lose control
over them, making it extremely difficult to make changes.  So we're restricting
the embed generation modal to a certain subset of users (for now), but a savvy
user could simply modify an existing public embed to plug in another comment
id, which would defeat the point of restricting it.  Enter hmac.

We know generate a unique token for each comment, and only by using the
appropriate token will your embed work.  This will be transparent to users, as
its just another piece of the html that they copy and paste onto their website.

Performance-wise, we're generating tokens for every comment that can be
embedded.  However, for now that's a limited set, and the operation is pretty
fast (roughly 5ms for 1000 tokens on my dev VM); if that becomes a problem, we
can easily take this code out after we no longer need the restriction.
This commit is contained in:
xiongchiamiov
2015-01-14 12:24:23 -08:00
committed by David Wick
parent e454857b31
commit e29e727791
5 changed files with 20 additions and 2 deletions

View File

@@ -21,6 +21,8 @@ websocket = YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5
true_ip =
# secret for authenticating private media embeds
media_embed = YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5
# secret for authenticating comment embeds
comment_embed = YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5
# secret for authenticating controller#action name
action_name = YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5
# secrets for communicating with Stripe (optional payment processor)

View File

@@ -1,7 +1,11 @@
import hashlib
import hmac
from pylons import c, g, request
from pylons.controllers.util import abort
from r2.controllers.reddit_base import UnloggedUser
from r2.lib.utils import constant_time_compare
from r2.models.subreddit import Subreddit
@@ -18,7 +22,8 @@ def can_embed(thing):
def setup_embed(thing):
if request.GET.get("embed") == "true":
embed_key = request.GET.get('embed')
if embed_key:
if request.host != g.media_domain:
# don't serve up untrusted content except on our
# specifically untrusted domain
@@ -27,6 +32,11 @@ def setup_embed(thing):
if not can_embed(thing):
abort(404)
expected_mac = hmac.new(g.secrets['comment_embed'], thing._id36,
hashlib.sha1).hexdigest()
if not constant_time_compare(embed_key or '', expected_mac):
abort(401)
c.render_style = "iframe"
c.user = UnloggedUser([c.lang])
c.user_is_loggedin = False

View File

@@ -20,6 +20,9 @@
# Inc. All Rights Reserved.
###############################################################################
import hashlib
import hmac
from r2.lib.db.thing import NotFound
from r2.lib.menus import (
JsButton,
@@ -180,6 +183,8 @@ class CommentButtons(PrintableButtons):
data={
"media": g.media_domain or g.domain,
"comment": thing.permalink,
"token": hmac.new(g.secrets['comment_embed'], thing._id36,
hashlib.sha1).hexdigest(),
"link": thing.link.make_permalink(thing.subreddit),
"title": thing.link.title,
"root": ("true" if thing.parent_id is None else "false"),

View File

@@ -46,6 +46,7 @@
var embedCodeTemplate = _.template(
'<div class="reddit-embed" ' +
' data-embed-token="<%- token %>"' +
' data-embed-media="<%- media %>" ' +
'<% if (parent) { %> data-embed-parent="true" <% } %>' +
'<% if (live) { %> data-embed-live="true" <% } %>' +

View File

@@ -31,7 +31,7 @@
context++;
}
var query = 'embed=true' +
var query = 'embed=' + data.embedToken +
'&context=' + context +
'&depth=' + (++context) +
'&showedits=' + data.embedLive +