Does exposing a session ID create a security risk?
Not necessarily. You're exposing session id's to the browser whenever you store a session id in a cookie. This is how sessions work - the browser needs to know the session id in order to send it back to the server. The question is how you're exposing your session id. If you're sending it in cookies, that's fine - everybody does that. It's a bigger risk if you're sending the session ID as an URL parameter in a GET request (like you do when you use your image solution), because the session ID can end up in various places which you didn't expect (proxy logs, server logs, browser history etc).
I'm looking to make a cross-domain + single app login, since you can't store cookies on other domains from one website, I'm using img tags with a href link to each website (eg: example.com/setsessionid?id=XXXX)
There's another way to do it (look into how the OAuth protocol works) which involves some clever HTTP redirects and basically works like this:
- Build your login page which does authentication. Have it accept a client identifier and a sufficiently long random nonce.
- Each of your other domains redirect to that login page when a user wants to login, using their client id and a random nonce, which they must store.
- The login service lets the user login, and when username and password are correct, it redirects back to a "successfully-logged-in"-url on the client domain. The login service knows where to redirect to because the client domain passed the client id, which you can use to look up where to redirect to. The login service sends a few parameters along, such as the user id of the user that logged in and the (unchanged) random nonce.
- The "successfully logged in"-url back on the client domain must accept and check the random nonce that was originally sent. If the nonces don't match, it must not accept the request. Otherwise, it can assume the login service correctly authenticated the user and can create an authenticated session cookie for it's own domain.
Depending on whether or not you want to provide single sign on, the login service can set it's own authentication cookie so that when the second domain redirects to the login page, the cookie is sent along and the login service can redirect to the success url immediately without asking for username and password.
This is extensible - e.g. it also works when you decouple the login service from the rest of your system and move it to a cloud service in Honolulu. And once you've built it, you can use it to let any web application authenticate using your user database, no matter where it's hosted - just add a new client id and redirect url to your login service.
You can also make it more secure by having the login service talk with the client domain directly, for example to have the client domain authenticate itself to the login service (e.g. not through the user's browser, but server-to-server) in addition to passing the random nonce - in your case, this is really easy since the login service and all the other services are hosted on the same machine, so you can simply set some flags in the database backend or create a file in the filesystem.
Also note that the system I described is only secure if the login service is reachable over https, because otherwise a MITM can simply steal the random nonce and use it to authenticate himself. But obviously thats a smart thing to do anyway, because if you don't encrypt the login page, a MITM can also just read the username and password the user sends in the clear.