Google App Engine - 安全Cookie [英] Google App Engine - Secure Cookies

查看:175
本文介绍了Google App Engine - 安全Cookie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找在Google App Engine中进行基于Cookie的身份验证/会话的方法,因为我不喜欢基于内存缓存的会话的想法,我也不喜欢强制用户创建google的想法帐户只是使用网站。我偶然发现了某人的发帖从Tornado框架中提到了一些签名的cookie函数,它看起来像我需要的。我想到的是将用户的ID存储在防篡改cookie中,并且可能使用装饰器来请求处理程序来测试用户的认证状态,并且作为附带好处,用户ID将可用于请求处理程序数据存储工作等。这个概念将类似于ASP.NET中的表单认证。这个代码来自Tornado框架的web.py模块。

I'd been searching for a way to do cookie based authentication/sessions in Google App Engine because I don't like the idea of memcache based sessions, and I also don't like the idea of forcing users to create google accounts just to use a website. I stumbled across someone's posting that mentioned some signed cookie functions from the Tornado framework and it looks like what I need. What I have in mind is storing a user's id in a tamper proof cookie, and maybe using a decorator for the request handlers to test the authentication status of the user, and as a side benefit the user id will be available to the request handler for datastore work and such. The concept would be similar to forms authentication in ASP.NET. This code comes from the web.py module of the Tornado framework.

根据docstrings,它标记和时间戳一个cookie,所以它不能被伪造和$ b $ b返回给定的签名cookie,如果它验证或无。

According to the docstrings, it "Signs and timestamps a cookie so it cannot be forged" and "Returns the given signed cookie if it validates, or None."

我试图在App Engine项目中使用它,但我不明白试图让这些方法在请求处理程序的上下文中工作的细微差别。有人可以告诉我正确的方法来做到这一点,而不会失去FriendFeed开发人员提供的功能? set_secure_cookie和get_secure_cookie部分是最重要的,但也可以使用其他方法。

I've tried to use it in an App Engine Project, but I don't understand the nuances of trying to get these methods to work in the context of the request handler. Can someone show me the right way to do this without losing the functionality that the FriendFeed developers put into it? The set_secure_cookie, and get_secure_cookie portions are the most important, but it would be nice to be able to use the other methods as well.

#!/usr/bin/env python

import Cookie
import base64
import time
import hashlib
import hmac
import datetime
import re
import calendar
import email.utils
import logging

def _utf8(s):
    if isinstance(s, unicode):
        return s.encode("utf-8")
    assert isinstance(s, str)
    return s

def _unicode(s):
    if isinstance(s, str):
        try:
            return s.decode("utf-8")
        except UnicodeDecodeError:
            raise HTTPError(400, "Non-utf8 argument")
    assert isinstance(s, unicode)
    return s 

def _time_independent_equals(a, b):
    if len(a) != len(b):
        return False
    result = 0
    for x, y in zip(a, b):
        result |= ord(x) ^ ord(y)
    return result == 0

def cookies(self):
    """A dictionary of Cookie.Morsel objects."""
    if not hasattr(self,"_cookies"):
        self._cookies = Cookie.BaseCookie()
        if "Cookie" in self.request.headers:
            try:
                self._cookies.load(self.request.headers["Cookie"])
            except:
                self.clear_all_cookies()
    return self._cookies

def _cookie_signature(self,*parts):
    self.require_setting("cookie_secret","secure cookies")
    hash = hmac.new(self.application.settings["cookie_secret"],
                    digestmod=hashlib.sha1)
    for part in parts:hash.update(part)
    return hash.hexdigest()

def get_cookie(self,name,default=None):
    """Gets the value of the cookie with the given name,else default."""
    if name in self.cookies:
        return self.cookies[name].value
    return default

def set_cookie(self,name,value,domain=None,expires=None,path="/",
               expires_days=None):
    """Sets the given cookie name/value with the given options."""
    name = _utf8(name)
    value = _utf8(value)
    if re.search(r"[\x00-\x20]",name + value):
        # Don't let us accidentally inject bad stuff
        raise ValueError("Invalid cookie %r:%r" % (name,value))
    if not hasattr(self,"_new_cookies"):
        self._new_cookies = []
    new_cookie = Cookie.BaseCookie()
    self._new_cookies.append(new_cookie)
    new_cookie[name] = value
    if domain:
        new_cookie[name]["domain"] = domain
    if expires_days is not None and not expires:
        expires = datetime.datetime.utcnow() + datetime.timedelta(
            days=expires_days)
    if expires:
        timestamp = calendar.timegm(expires.utctimetuple())
        new_cookie[name]["expires"] = email.utils.formatdate(
            timestamp,localtime=False,usegmt=True)
    if path:
        new_cookie[name]["path"] = path

def clear_cookie(self,name,path="/",domain=None):
    """Deletes the cookie with the given name."""
    expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
    self.set_cookie(name,value="",path=path,expires=expires,
                    domain=domain)

def clear_all_cookies(self):
    """Deletes all the cookies the user sent with this request."""
    for name in self.cookies.iterkeys():
        self.clear_cookie(name)

def set_secure_cookie(self,name,value,expires_days=30,**kwargs):
    """Signs and timestamps a cookie so it cannot be forged"""
    timestamp = str(int(time.time()))
    value = base64.b64encode(value)
    signature = self._cookie_signature(name,value,timestamp)
    value = "|".join([value,timestamp,signature])
    self.set_cookie(name,value,expires_days=expires_days,**kwargs)

def get_secure_cookie(self,name,include_name=True,value=None):
    """Returns the given signed cookie if it validates,or None"""
    if value is None:value = self.get_cookie(name)
    if not value:return None
    parts = value.split("|")
    if len(parts) != 3:return None
    if include_name:
        signature = self._cookie_signature(name,parts[0],parts[1])
    else:
        signature = self._cookie_signature(parts[0],parts[1])
    if not _time_independent_equals(parts[2],signature):
        logging.warning("Invalid cookie signature %r",value)
        return None
    timestamp = int(parts[1])
    if timestamp < time.time() - 31 * 86400:
        logging.warning("Expired cookie %r",value)
        return None
    try:
        return base64.b64decode(parts[0])
    except:
        return None

uid = 1234 | 1234567890 | d32b9e9c67274fa062e2599fd659cc14

uid=1234|1234567890|d32b9e9c67274fa062e2599fd659cc14

部件:

1. uid是键的名称

2. 1234是您的值clear < br>
3. 1234567890是时间戳

4. d32b9e9c67274fa062e2599fd659cc14是从值和时间戳签名

Parts:
1. uid is the name of the key
2. 1234 is your value in clear
3. 1234567890 is the timestamp
4. d32b9e9c67274fa062e2599fd659cc14 is the signature made from the value and the timestamp

推荐答案

如果任何人感兴趣,则可以使用:

This works if anyone is interested:

from google.appengine.ext import webapp

import Cookie
import base64
import time
import hashlib
import hmac
import datetime
import re
import calendar
import email.utils
import logging

def _utf8(s):
    if isinstance(s, unicode):
        return s.encode("utf-8")
    assert isinstance(s, str)
    return s

def _unicode(s):
    if isinstance(s, str):
        try:
            return s.decode("utf-8")
        except UnicodeDecodeError:
            raise HTTPError(400, "Non-utf8 argument")
    assert isinstance(s, unicode)
    return s 

def _time_independent_equals(a, b):
    if len(a) != len(b):
        return False
    result = 0
    for x, y in zip(a, b):
        result |= ord(x) ^ ord(y)
    return result == 0


class ExtendedRequestHandler(webapp.RequestHandler):
    """Extends the Google App Engine webapp.RequestHandler."""
    def clear_cookie(self,name,path="/",domain=None):
        """Deletes the cookie with the given name."""
        expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
        self.set_cookie(name,value="",path=path,expires=expires,
                        domain=domain)    

    def clear_all_cookies(self):
        """Deletes all the cookies the user sent with this request."""
        for name in self.cookies.iterkeys():
            self.clear_cookie(name)            

    def cookies(self):
        """A dictionary of Cookie.Morsel objects."""
        if not hasattr(self,"_cookies"):
            self._cookies = Cookie.BaseCookie()
            if "Cookie" in self.request.headers:
                try:
                    self._cookies.load(self.request.headers["Cookie"])
                except:
                    self.clear_all_cookies()
        return self._cookies

    def _cookie_signature(self,*parts):
        """Hashes a string based on a pass-phrase."""
        hash = hmac.new("MySecretPhrase",digestmod=hashlib.sha1)
        for part in parts:hash.update(part)
        return hash.hexdigest() 

    def get_cookie(self,name,default=None):
        """Gets the value of the cookie with the given name,else default."""
        if name in self.request.cookies:
            return self.request.cookies[name]
        return default

    def set_cookie(self,name,value,domain=None,expires=None,path="/",expires_days=None):
        """Sets the given cookie name/value with the given options."""
        name = _utf8(name)
        value = _utf8(value)
        if re.search(r"[\x00-\x20]",name + value): # Don't let us accidentally inject bad stuff
            raise ValueError("Invalid cookie %r:%r" % (name,value))
        new_cookie = Cookie.BaseCookie()
        new_cookie[name] = value
        if domain:
            new_cookie[name]["domain"] = domain
        if expires_days is not None and not expires:
            expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days)
        if expires:
            timestamp = calendar.timegm(expires.utctimetuple())
            new_cookie[name]["expires"] = email.utils.formatdate(timestamp,localtime=False,usegmt=True)
        if path:
            new_cookie[name]["path"] = path
        for morsel in new_cookie.values():
            self.response.headers.add_header('Set-Cookie',morsel.OutputString(None))

    def set_secure_cookie(self,name,value,expires_days=30,**kwargs):
        """Signs and timestamps a cookie so it cannot be forged"""
        timestamp = str(int(time.time()))
        value = base64.b64encode(value)
        signature = self._cookie_signature(name,value,timestamp)
        value = "|".join([value,timestamp,signature])
        self.set_cookie(name,value,expires_days=expires_days,**kwargs)

    def get_secure_cookie(self,name,include_name=True,value=None):
        """Returns the given signed cookie if it validates,or None"""
        if value is None:value = self.get_cookie(name)
        if not value:return None
        parts = value.split("|")
        if len(parts) != 3:return None
        if include_name:
            signature = self._cookie_signature(name,parts[0],parts[1])
        else:
            signature = self._cookie_signature(parts[0],parts[1])
        if not _time_independent_equals(parts[2],signature):
            logging.warning("Invalid cookie signature %r",value)
            return None
        timestamp = int(parts[1])
        if timestamp < time.time() - 31 * 86400:
            logging.warning("Expired cookie %r",value)
            return None
        try:
            return base64.b64decode(parts[0])
        except:
            return None

class MyHandler(ExtendedRequestHandler):
    def get(self):
        self.set_cookie(name="MyCookie",value="NewValue",expires_days=10)
        self.set_secure_cookie(name="MySecureCookie",value="SecureValue",expires_days=10)

        value1 = self.get_cookie('MyCookie')
        value2 = self.get_secure_cookie('MySecureCookie')

这篇关于Google App Engine - 安全Cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆