bungle / lua-resty-session

Session library for OpenResty – flexible and secure
BSD 2-Clause "Simplified" License
320 stars 111 forks source link

Session Example is not working #23

Closed hulu1522 closed 8 years ago

hulu1522 commented 8 years ago

I have been trying a lot to figure out why my cookies were not working. I followed the documentation and still something seems to be going wrong when I 'open' a cookie before starting it. It would fail every time. I decided to test your code in the example and it is not working either. I just get "Anonymous" every time. Why is that? Thanks.

bungle commented 8 years ago

You mean, you have tried this (and you have nothing else there?): https://github.com/bungle/lua-resty-session#hello-world-with-lua-resty-session

hulu1522 commented 8 years ago

yes... That is why i'm so confused.

bungle commented 8 years ago

I just tried it, and it works just fine.

Your nginx.conf is exactly just this, and nothing more? https://github.com/bungle/lua-resty-session#hello-world-with-lua-resty-session

Do you have session.lua file and session directory in your lualib/resty directory?

Do you get any errors in error.log?

bungle commented 8 years ago

Are you running OpenResty or something else? Latest OpenResty should be fine. E.g. this: https://openresty.org/download/ngx_openresty-1.9.7.2rc1.tar.gz

How have you compiled it?

hulu1522 commented 8 years ago

Well, I don't know why your example wasn't working but I just got mine to work. It turns out mine had an issues because of the cookie domain that was being set. Thanks for the help. I am using openresty but it is built with a Chef cookbook. I was also wondering if there was any setting to disable the cookie renew? Thanks.

bungle commented 8 years ago

cookie renew can be skipped by just calling open and not start, and you can manually send a new one with save, but without renewing the sessions will be gone when the lifetime ends if you don't call save (or start).

hulu1522 commented 8 years ago

What about the default setting of $session_cookie_renew? Won't that trigger a new cookie save? How can I just turn that off?

bungle commented 8 years ago

No it doesn't. It is only used in start. If you never call start the renewing will not take a place.

bungle commented 8 years ago

This is the renewing code: https://github.com/bungle/lua-resty-session/blob/master/lib/resty/session.lua#L271-L273

Basically start just checks if the cookie is expiring, and will call save if it needs to send a new cookie. If you don't call start then you don't send new cookies unless you call save.

There is no triggers to which to attach in OpenResty.

hulu1522 commented 8 years ago

That is good to know, Thanks. There is also this error which for some reason keeps clearing the cookie: ignoring stale global SSL error (SSL: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt)

Have you seen that and do you have any idea why it would clear a persistent cookie?

bungle commented 8 years ago

Are you running with default config, aka not setting anything for ciphers? I have not seen that before. Have you tried disabling this:

set $session_check_ssi off;

I may turn it off by default in future releases, as it seems to cause some problems.

Also it is a good idea to set session_secret (change the below to your own secret):

set $session_secret 623q4hR325t36VsCD3g567922IC0073T;

Are you running on what platform, and what OpenSSL?

hulu1522 commented 8 years ago

Yes that is off.

bungle commented 8 years ago

I think that EVP_DecryptFinal_ex:bad decrypt just means that decrypt key is invalid. At some point I will move to Encrypt-Then-MAC that will probably get rid of this error. You should ignore it. It just means that decryption failed, and session will start as a new. When does that clearing happen? Have you restarted OpenResty or not set session_secret?

hulu1522 commented 8 years ago

@bungle Thanks for the info. It seems we have narrowed the errors down and lua-resty-session is failing to open the original cookie at random times. Here is what we have to test (portions):

--> Get Session <--
::session_open_retry::
session = require("resty.session").new()
session:open()

if not session.present and not info.args.accesskey then
  local cookie = ngx.req.get_headers()["Cookie"]
  if cookie then
    ngx.log(ngx.ERR, "*** RETRY OPEN SESSION ****")
    goto session_open_retry
  end
end

-- other code that will save the cookie

We know the cookie is present because it is found in the header of the current request and retries:

2016/01/13 15:04:17 [error] 7236#0: *541 [lua] access.lua:30: *** RETRY OPEN SESSION ****, client: 10.130.5.41, server: <server>, request: "POST /elasticsearch/.kibana/_search HTTP/1.1", host: "<server>", referrer: "https://<server>/"
2016/01/13 15:04:17 [error] 7236#0: *541 [lua] access.lua:30: *** RETRY OPEN SESSION ****, client: 10.130.5.41, server: <server>, request: "POST /elasticsearch/.kibana/_search HTTP/1.1", host: "<server>", referrer: "https://<server>/"
2016/01/13 15:04:17 [error] 7236#0: *541 [lua] access.lua:30: *** RETRY OPEN SESSION ****, client: 10.130.5.41, server: <server>, request: "POST /elasticsearch/.kibana/_search HTTP/1.1", host: "<server>", referrer: "https://<server>/"

Yes it is an infinite loop but the cookie being present is causing the loop.

bungle commented 8 years ago

If it fails, clearly the cookie is invalid. It is not something like this randomly fails, there is a reason and most likely reason is that cookie is invalid, expired, server config has changed, cookie is tampered, different configs on servers, server is restarted when session_secret is not set, server side cookie store (if used) is flushed or cannot be connected, user agent string is changed, page is requested in different schema like http vs. https etc.

hulu1522 commented 8 years ago

I'm going to close this. I agree with you about that but I could not find out why it was failing. I wrote my own session handler using redis and not encrypting and decrypting every time. Everything seems to be working. The cookie itself is just a key to access the real information in Redis. I also tested all of your checks and they work just fine also. It must have been a combination of too many requests too fast and number of connections. I really could not tell you why it was happening. Thanks a ton for you help though.

bungle commented 8 years ago

You can disable encryption with lua-resty-session as well. Cookie being just a key is not very secure approach.

bungle commented 8 years ago

Can I produce the same error you were having somehow? You could add ngx.log statements in session code to see where it fails.

bungle commented 8 years ago

And did you run multiple servers and or multiple worker processes? I'd like to fix this if there is really a problem in lua-resty-session, but so far well, too little information. Can you give me an example that I could try?

hulu1522 commented 8 years ago

I'll see what I can get you. To answer your questions: Single server but it does spin up multiple workers. From my testing it was failing when opening the session. I should have put logging into the session.lua code. What I did to test it was open using session and compare the data that should be there. I save data into the cookie. Every time it failed there was no data in the newly opened session but the cookie was present in the headers. At that point the cookie was invalid. Either the data was not saved back to the cookie or it was not opened correctly. I didn't have a lot of time to fix the issue but I may be able to do some more testing. I was verifying the cookie on every request.

bungle commented 8 years ago

If you can give me your full config and example that would help. But I suppose that you have:

  1. one nginx server
  2. multiple workers
  3. you are using default encryption setting

Now what kind of configs have you set for lua-resty-session?

First of all, does this problem happen when you disable cipher, e.g?

set $session_cipher none;

If it does not, then we have narrowed your problem down to encryption and decryption.

Now I have asked many times, do you have session_secret defined (check that it is correct length, e.g. the length just like below 32 chars):

set $session_secret 623q4hR325t36VsCD3g567922IC0073T;

Because otherwise it is possible that different workers use different autogenerated secret, and then if you request goes to other worker, then the decryption obviously fails.

If anything fails in session.open, a new session is opened with data being empty. That's what is a correct thing to do. Cookie can be present, but it is invalid. Data will be saved correctly that's for sure. The problem here is that your cookie is invalid. But because you don't give me all the information, I cannot really help. Like all the settings you have in nginx related to session. I still suspect you didn't define session_secret. But it can be other things as well. If you enable ciphers can you try disabling the additional checks to see if the problem is with them:

set $session_check_ssi         off;
set $session_check_ua          off;
set $session_check_scheme      off;
set $session_check_addr        off;
bungle commented 8 years ago

If you use server side session the cipher can be turned to none for better performance if you trust that no other processes can get access to you backend. For cookies sessions it should be on, because otherwise if is easy to tamper your cookie.

hulu1522 commented 8 years ago

Thanks for the info. Setting session_secret seemed to fix the random invalid session problem.

liweitianux commented 2 years ago

Hi. Just for the record. I'm having the similar issue with APISIX + openid-connect plugin, which uses lua-resty-openidc that depends on this lua-resty-session.

The phenomenon is something like:

  1. visit a protected URL
  2. openidc redirect to OP to authenticate user
  3. login and redirect back openidc
  4. obtain tokens and save to session
  5. redirect to the original URL
  6. repeatedly retry to visit the protected URL; sometimes it just works, but sometimes it redirects to OP for another auth, although the token is still valid.

After adding extra debugs and I found out it was caused by the decryption failure of the existing cookie session in strategy.load().

After more investigation, it turned out the decryption failure was caused by the different auto-generated secrets of different worker processes. When the $session_secret is not configured, every worker process would auto generate its own secret and thus different between each other. As a consequence, the cookie session created on worker A cannot be decrypted by worker B, and thus the above phenomenon and this issue.

So one solution is explicitly set $session_secret in the Nginx config file, as already suggested above by @bungle.

Another solution I think is to load this module in the init_by_lua phase, i.e., before spawning the worker processes, so that all workers gain the same session secret.

Cheers.

liweitianux commented 2 years ago

Hi @bungle, it seems it should be mentioned in README the issue of sharing session secret across multiple worker processes, e.g., the recommended ways to achieve the secret sharing among all workers. The example uses only one worker, but there are always multiple workers in production setups.

Thanks.