digitally signed urls

187 views
Skip to first unread message

Pierre

unread,
Nov 8, 2017, 7:33:16 AM11/8/17
to web2py-users
hello everyone,

As I understand it, purpose of digital signature is to prevent urls exposure outside application workflow context. One way to sign involves Auth and the simplest one can be achieved without Auth ( this is what I find interesting since there's not a handy technique to prevent session from ending before it's supposed to ). Now if i look closer at this 'no-auth' option the hmac key used for signing is turned into an application constant (correct me if i am wrong) whereas it's dynamic and session specific in the former case, so that a 'no-auth' signed url is always valid and thus the question why should it be signed ?


http://web2py.com/books/default/chapter/29/04/the-core#Digitally-signed-urls

Leonel Câmara

unread,
Nov 8, 2017, 9:52:18 AM11/8/17
to web2py-users
I'll give you an example, lets imagine I have a client database. I want to send a survey to my clients and I want the survey results to be associated with their profile in my database (note that my clients do not have users in my system). I send each one an email with a digitally signed URL, the signature is specific to the client, now when the client fills the form I can associate it with his row in my database.  
  
It is true that anyone can access it if they have the link, the security is with the secrecy of link, in this case I would be relying that only my clients would have access to their emails.  

Anthony

unread,
Nov 8, 2017, 10:02:33 AM11/8/17
to web2py-users
Another possible use case -- suppose your application generates various links to a particular action with different combinations of URL args and vars and wants to limit access to that action so only the explicitly generated links will work (i.e., prevent users from generating their own combinations of args and vars). You can digitally sign the allowed URLs and check the signature in the action to prevent any other URLs from working.

Anthony

Pierre

unread,
Nov 8, 2017, 11:17:37 AM11/8/17
to web2py-users
yes of course but Leonel your use-case looks very similar to the Auth case (i mean user_signature=true + @auth.requires_signature) . It's also a one hmac_key per user|client case. Actually i am not so much interested in why should a url be signed: what i'd like to achieve is mimic Auth signature case in the context of 'no-auth' signature. I've found this post:

https://groups.google.com/forum/#!msg/web2py/xnKA-4nnfeM/0OrWhCEInxsJ

and right now i am generating a session.hmac_key via  auth.settings.login_onaccept = [generate_hmac_key] as Anthony suggested in this post
don't know if this is effective ? i guess this forbids usage of both @auth.requires_login and session.forget() in the same function
signature is very confusing.........and so is the session object (when is it alive?  when is it dead ?)



Anthony

unread,
Nov 8, 2017, 6:32:38 PM11/8/17
to web2py-users
On Wednesday, November 8, 2017 at 11:17:37 AM UTC-5, Pierre wrote:
yes of course but Leonel your use-case looks very similar to the Auth case (i mean user_signature=true + @auth.requires_signature) . It's also a one hmac_key per user|client case. Actually i am not so much interested in why should a url be signed: what i'd like to achieve is mimic Auth signature case in the context of 'no-auth' signature. I've found this post:

https://groups.google.com/forum/#!msg/web2py/xnKA-4nnfeM/0OrWhCEInxsJ

and right now i am generating a session.hmac_key via  auth.settings.login_onaccept = [generate_hmac_key] as Anthony suggested in this post
don't know if this is effective ?

It's not quite clear what you are trying to achieve. If you are using Auth and having users log in, why not use URL(..., user_signature=True) and @auth.requires_signature()? What is your desired workflow?
 
i guess this forbids usage of both @auth.requires_login and session.forget() in the same function

You should be able to use both. session.forget() simply prevents any changes in the session during the current request from being written to the session (it is often called as session.forget(response), which also unlocks the session file, enabling other requests to access the file).
 
signature is very confusing.........and so is the session object (when is it alive?  when is it dead ?)

Unless you completely disable sessions, the session object is always available in the web2py environment (though it may be empty). As noted above, you can prevent changes being written to the session within a given request by calling session.forget() -- but even after doing that, you can still access the content of the session.

Anthony

Pierre

unread,
Nov 9, 2017, 6:28:31 AM11/9/17
to web2py-users
here is the workflow schema, a little bit weird indeed:

@auth.requires_login()
def main_func():
    form
= SQLFORM(db.atable)
   
if form.process(onvalidation=..., dbio=False).accepted:
         rtn
= scheduler.queue_task(task_func,….)
         
if not rtn.id:      #there are errors
             
raise HTTP(404)
         
else:
             redirect
(URL('accept_func', args=[...]))
   
elif form.errors:
         
...
   
else:
         
...



accept_func calls an ajax: task_completed to test for task completion (rtn.id) every 5 seconds till task.status=='COMPLETED' or 'failure' (NOT COMPLETED after 5 calls)


If i make no mistake, there's a possiblity that auth.user expires before the entire process finishes so i am not sure it's a good idea to decorate accept_func (@auth.requires_login()) or task_completed (@auth.requires_signature())


right now accept_func works without decoration so it's mostly a 'task_completed signature issue' 


i might have missed something since the beginning ?

Anthony

unread,
Nov 9, 2017, 10:16:26 AM11/9/17
to web2py-users
@auth.requires_login()
def main_func():
    form
= SQLFORM(db.atable)
   
if form.process(onvalidation=..., dbio=False).accepted:
         rtn
= scheduler.queue_task(task_func,….)
         
if not rtn.id:      #there are errors
             
raise HTTP(404)
         
else:
             redirect
(URL('accept_func', args=[...]))
   
elif form.errors:
         
...
   
else:
         
...



accept_func calls an ajax: task_completed to test for task completion (rtn.id) every 5 seconds till task.status=='COMPLETED' or 'failure' (NOT COMPLETED after 5 calls)


accept_func is a web2py controller action, so it wouldn't be making Ajax requests, which must come from the browser. Is main_func an Ajax component (which would mean accept_func must also be an Ajax component)? Are you saying that once the accept_func component is loaded in the browser, it makes Ajax requests from the browser every 5 seconds to task_completed?
 


If i make no mistake, there's a possiblity that auth.user expires before the entire process finishes so i am not sure it's a good idea to decorate accept_func (@auth.requires_login()) or task_completed (@auth.requires_signature())


As long as you are making requests the login won't expire, as the expiration is measured from the time of the last request.

Anyway, if you want to use digital signatures, I don't see why you can't simply generate URLs with URL(..., user_signature=True) and then decorate both accept_func and task_completed with @auth.requires_signature().

Also, note that if you don't care about limiting a given user's requests based on the specific URL args and vars, you can simply decorate accept_func and task_completed with @auth.requires_login(). Digital signatures for URLs add extra protection in case you need to restrict access to only a particular URL (i.e., a particular combination of args and vars).

Anthony

Pierre

unread,
Nov 10, 2017, 7:47:42 AM11/10/17
to web2py-users

accept_func calls an ajax: task_completed to test for task completion (rtn.id) every 5 seconds till task.status=='COMPLETED' or 'failure' (NOT >COMPLETED after 5 calls)


accept_func is a web2py controller action, so it wouldn't be making Ajax requests, which must come from the browser. Is main_func an Ajax component (which would mean accept_func must also be an Ajax component)? Are you saying that once the accept_func component is loaded in the browser, it makes Ajax requests from the browser every 5 seconds to task_completed?
 
 
Yes you are right, it's accept_func.html that carries the js ajax calls code. No main_func is not an ajax component and  there are no components involved in the workflow.....
it's as follow: main-func loads the form. if form is accepted, it's processed via a scheduler task while user is redirected to accept_func till task is completed or failed



If i make no mistake, there's a possiblity that auth.user expires before the entire process finishes so i am not sure it's a good idea to decorate accept_func (@auth.requires_login()) or task_completed (@auth.requires_signature())


As long as you are making requests the login won't expire, as the expiration is measured from the time of the last request.
 

I don't know the maths web2py uses to calculate this ?
does this mean a logged in user is  logged out only if he stays idle (make no request) for the duration of auth.setting.expiration ?
what happens if user loads the form (main_func) logged in and hits the submit button logged out ( he is been on the phone ) ?

Anthony

unread,
Nov 10, 2017, 8:37:00 AM11/10/17
to web2py-users
As long as you are making requests the login won't expire, as the expiration is measured from the time of the last request.
 

I don't know the maths web2py uses to calculate this ?
does this mean a logged in user is  logged out only if he stays idle (make no request) for the duration of auth.setting.expiration ?

Correct. Technically, the expiration time is not extended on every single request but only if the time since last visit exceeds one tenth of the configured expiration time (this avoids writing to the session to record the last visit on every single request).
 
what happens if user loads the form (main_func) logged in and hits the submit button logged out ( he is been on the phone ) ?

They'll have to log in again.

Anthony

Pierre

unread,
Nov 10, 2017, 1:21:29 PM11/10/17
to web2py-users
thanks Anthony....
it makes things clearer...the main_func workflow can do without the extra decoration of accept_func and task_completed (using no-auth signature) but there's still an issue as request.ajax doesn't seem to recognize ajax calls....

Pierre

unread,
Nov 12, 2017, 1:09:29 PM11/12/17
to web2py-users
finally i backtracked to decorate everything along the 'chain'. It looks safer and i am concerned with security
thanks again
Reply all
Reply to author
Forward
0 new messages