Вопрос

Background:

I have the core functionality of a very simple vote-based site setup and working well in pyramid utilizing a sqlite database. The last requirement for this application is to allow only one vote per day, per user. It has been specified that this must be done via cookies, and that no users shall be allowed to vote on Saturdays or Sundays.

I am currently using UnencryptedCookieSessionFactoryConfig for session management and to handle flash messages.

Question:

I've identified that I need the following functionality, but can't determine what modules of pyramid might provide it (or if I should be looking elsewhere):

  • Create a cookie for each user that persists between browser sessions (I am aware this is insecure as a method of preventing multiple votes. That's fine.)

  • Allow a single vote to be placed per day, per user.

  • Give a new vote to a user once 24 hours has elapsed.

  • Prevent all voting if day of week = saturday or sunday (this should be trivial with the use of a datetime() check placed prior to any cookie-checking logic.

Additional Info:

My current db schema is as follows, and must stay this way:

create table if not exists games (
    id integer primary key autoincrement,
    title char(100) not null,
    owned bool not null,
    created char(40) not null
);

create table if not exists votes (
    gameId integer,
    created char(40) not null,
    FOREIGN KEY(gameId) REFERENCES games(id)
);

and the current vote function is as follows:

@view_config(route_name='usevote')
def usevote_view(request):
    game_id = int(request.matchdict['id'])
    request.db.execute('insert into votes (gameId,created) values (?,?)',
                (game_id,now))
    request.db.commit()
    request.session.flash('Your vote has been counted. You can vote again in 24 hours.')
    return HTTPFound(location=request.route_url('list'))

Thanks!

Это было полезно?

Решение

session data on cookies only

To integrate cookie sessions on pyramid, take a look on pyramid_beaker

To guarantee integrity only using cookies (and avoid the user poking into the cookie data), you should use an encrypted cookie (take a look into the Session Based Cookie and the Encryption Options).

Your main configuration will look somewhat like this:

[app:main]
...
session.type = cookie
session.key = SESSION
session.encrypt_key = R9RD9qx7uzcybJt1iBzeMoohyDUbZAnFCyfkWfxOoX8s5ay3pM
session.validate_key = pKs3JDwWiJmt0N0wQjJIqdG5c1XsHSlauM6T2DfB8FqOifsWZN
...

The session.key is just the name of the cookie. Change for whatever you want

The session.encrypt_key and session.validate_key above are just examples of big random strings. You should generate them yourself and keep them private.

Also, to encrypt the cookies properly you will need an AES cipher implementation. Installing pycrypto should do it:

pip install pycryto

Also your main function that creates the wsgi application should be changed to something like this:

from pyramid_beaker import session_factory_from_settings
...

def main(global_config, **settings):
    ...
    config = Configurator(settings=settings)
    ...
    config.set_session_factory(session_factory_from_settings(settings))

Now you can store the cookie data directly into the client browser and avoid data tampering. The simple solution to solve your problem is setting this cookie to never expire, storing the date of the last time he voted inside it and check based on what day is today and what day did he last voted

the main issue

The main problem now is dealing with users that delete the cookie, use another browser or simple use the browser's incognito window (chrome) or private navigation (firefox). This user appears to be a new user to your system and thus can vote again.

IMO to solve that you will need to have a server side control or penalize the user in a way that deleting the cookie will actually make his life harder to the point that deleting the cookie to gain a vote is not desirable anymore.

Security is not about perfect unhackable systems, but building systems that the cost to bypass it is actually higher than the benefit of doing it.

Другие советы

Using cookies for that kind of control will not prevent even the most simple attack (using a different browser for example :)). But you seem to know it and not actually care so it should be fine I guess:

Everytime a user votes, add a field to the cookie (you should also set its age limit to at least a week) with the value of the current date.

Next time the user tries to vote, you check if it's Saturday or Sunday (according to the user time settings),if that field exists and if the value is older than one day.

If you set the cookie validity to the next Saturday, you will have an extra verification mechanism as the cookie won't be valid anyway if it's Saturday :)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top