• Home
  • Учебник по ExtJS
  • О сайте
  •  


    Вопрос доверия

    Август 26th, 2008

    Процесс разработки приложения под Google App Engine замечателен во многих смыслах: он интересен, а приложение легко масштабируется и доступно огромному числу пользователей по всему миру. Если у вас есть аккаунт Gmail, вы можете пройти авторизацию на сайте, использующем App Engine.

    А что можно сделать, чтобы не пускать кого попало в наше приложение? К примеру, представьте, что вы создали небольшой сайт, который хотите открыть только для членов семьи и своих друзей. Каким образом можно предотвратить доступ для всех других?

    Одним из решений проблемы является составление списка разрешенных пользователей (либо получения его из базы данных). Это годится в том случае, если вы знаете кто же допущен к сайту, но к сожалению требует постоянного изменения этого списка и поддержания его в актуальном состоянии. Другим интересным методом является использование системы инвайтов (приглашений), как той, какую на начальном этапе имел Gmail, но это тоже означает, что-то должен управлять этими приглашениями. Следующий пример показывает работу золотой середины между этими описанными методами — технология, названная HMAC, которая позволяет убедиться, конкретный аккаунт Google имеет право доступа.

    Следующий код создает криптографический хэш для заданного имени порльзователя. Он использует удобный метод из модуля cryptutil, который сам является частью примера кода OpenID. В процессе работы приложение оперирует секретным ключом, который ни в коем случае не должен быть опубликован. К конечному пользователю передается только сгенерированная хэш-строка:

    import base64
    from openid import cryptutil
    
    def sign(username):
    
      # В реальной жизни выберите лучший секретный ключ!
      secret='superSecretKey'
      return base64.encodestring(
          cryptutil.hmacSha1(secret, username))
    
    

    Так как эта проверка работает на практике? Давайте посмотрим на простой обработчик запросов, который будет использовать ее:

    import cgi
    import os
    import urllib
    import wsgiref.handlers
    
    from google.appengine.api import users
    from google.appengine.ext import webapp
    
    class MainPage(webapp.RequestHandler):
    
      def isValid(self):
        """Определение, что заданный запрос валиден.
    
           Для выполнения этих критериев, текущий пользователь должен
           быть авторизован и быть либо администратором, либо передать
           в запросе зашифрованный параметр, совпадающий с его именем пользователя.
        """
        user = users.get_current_user()
        if not user:
          return False
        if not users.is_current_user_admin():
          expected_signature = sign(user.email().lower())
          given_signature = self.request.get('signature')
          if not given_signature == expected_signature:
            return False
        return True
    
    

    Наш метод выполняет проверку, имеет ли данный запрос параметр с подписью. Если да, он сравнивает его с хэшем, вычисленным из адреса электронной почты текущего пользователя. И только в том случае, если оба этих ключа совпадают, пользователю предоставляется доступ.

    Следующие методы get и post показывают работу простейшего приложения, отображающего важное сообщение только для приглашенных пользователей. Введя адрес электронной почты другого пользователя, мы позволяем системе создать подписанный URL, который затем будет передан приглашаемому пользователю:

      def get(self):
        """Отображение сообщения только для приглашенных пользователей."""
    
        # Требуется авторизация
        user = users.get_current_user()
        if not user:
          self.redirect(users.create_login_url(self.request.uri))
          return
    
        # Если пользователь не администратор, проверить подпись
        if not self.isValid():
          self.error(403)
          return
    
        # Ok, пользователь допущен к просмотру страницы!
        # В реальной жизни мы воспользуемся в этом месте
        # шаблоном ;-)
        self.response.out.write("""
            <html><body>
            <h1>Hello, %s</h1>
            <p>Ниже секретное сообщение, которое вы ищете:
               &nbsp;<b>APP ENGINE РУЛИТ!!!</b>
            </p>
            <form method="POST">
            Передать сообщение другу
            <input name="invitee"/> &nbsp;
            <input type="submit"/></form>
            <p><a href="%s">Log out</a></p>
            </body></html
            """ % (cgi.escape(user.nickname()),
                   users.create_logout_url(self.request.uri)))
    
      def post(self):
        """Создание строки URL для последующей отправки приглашенному."""
    
        # Если пользователь не администратор, проверить подпись
        if not self.isValid():
          self.error(403)
          return
    
        # Получить имя invitee
        invitee = self.request.get('invitee')
        if not invitee:
          invitee = 'anonymnous'
        invitee = invitee.lower()
    
        # подписать инвайт и вывести url
        signature = sign(invitee)
        self.response.out.write("""
            <html><body>
            URL для друга:
            http://%s?signature=%s</body></html>""" % (
                os.environ['SERVER_NAME'],
                urllib.quote(signature, '')))
    
    

    Несмотря на то, что это выглядит игрушечным приложением, этот пример показывает практический подход, который может быть использован для современных веб-приложений в ответ на вопрос: как можно проверить, что запрос пришел из надежного источника. Для более комплексного алгоритма обратитесь к спецификации OAuth, в которой описываются подходы использования подписи веб-запросов с помощью HMAC.




    App Engine и шифрование

    Август 5th, 2008

    Оригинал статьи – http://blog.appenginefan.com/2008/04/appengine-and-encryption.html

    Одна из наиболее значимых возможностей, которую просят компанию Google реализовать в первую очередь разработчики в AppEngine – это поддержка шифрования через SSL. Хотя и нет сомнений, что она будет реализована в ближайшее время, хотелось бы изучить варианты того, как можно сделать работу приложения безопаснее в текущей версии. По крайней мере в век Web 2.0 не может быть ничего невозможного.

    Представьте, что мы начинаем разработку с нуля нового приложения. Большая часть данных приложения не требует никакого шифрования (страницы html, логотип компании, стили css…). Давайте предположим, что нас не пугает Javascript и попробуем его задействовать для обмена информацией через XmlHttpRequest. Что мешает нам шифровать все данные, до того, как они будут переданы через сеть? Таким образом необходимо, чтобы и клиент, и сервер выбрали общий метод шифрования данных.

    Необходимые ингредиенты:

    (Я не проводил тестирование этих компонентов, поэтому вам необходимо сделать это самостоятельно).

    Представьте что приложение работает под AppEngine и мы загрузили вместе с его кодом пару публичный/приватный ключ. Ничто не мешает нам сделать следующее:

    • поместить публичный ключ в один из файлов со скриптами Javascript, которые загружаются вместе с приложением. В этом случае, код на Javascript в клиенте может зашифровать данные, отправляемые в сторону сервера.
    • после инициализации, клиент на Javascript создает случайный ключ для шифрования по алгоритму AES. Он шифрует эти данные с использованием публичного ключа сервера и сохраняет их в cookie, отправляемый серверу.
    • мы создаем собственную версию функции XmlHttpRequest, которая будет шифровать все данные с помощью AES до того, как отправлять их в сеть
    • сервер получает зашифрованные данные, извлекает ключ из зашифрованного cookie и использует его для расшифровки данных
    • когда серверу требуется отправить данные обратно, он использует полученный ключ от клиента и зашифровывает им сообщение

    Я не пробовал этот метод в реальной работе, поэтому не имею ни малейшего представления, какое это может оказать влияние на квоты приложения (процедура шифрации/дешифрации на чистом языке Python может отнимать много ресурсов). Также неизвестно, как быстро будет работать AES на строне клиента. Если кто-нибудь, попробовал реализовать эти идеи в жизнь, дайте знать.