I am trying to get my head around secure authentication. Here is the safest method I can think of.
Send an encrypted username + SHA-256ed password to the server and wait for a yes / no response. But the problem with this is a hacker could hack the response to be a yes when it should be a no, giving them unauthorized access to that account.
I am thinking you could work around it by encrypting the response and then, instead of storing it in a Boolean, calling a function that changes state of the application. But because the hacker can make the server say no and yes from his control he can find out the encryption key and still change the result.
That seems kind of insecure, right? What’s stopping the hacker from isolating the function that logs you in or the Boolean?
Or am I just being naive and everything really is that insecure? I suppose the only real safe way to do it is to store if the user passed authentication on the authorization server and do a quick Boolean check to see if the user is logged in before every server action.
As Banthar said in his comment, the authorization check should always be performed on the server.
The standard way of implementing this kind of thing is by using a token: the client sends a username and password to the server. If the credentials given by the client succeed authentication, then the server generates a security token, stores it somewhere for later chacks and also sends the token back to the client. For every following request to the server, the client should send the token along with the request parameters, allowing the server to check if the token is valid. The server executes the request only if it can verify that the token is legitimate and authorized, any doubt should result in the server revoking the token.
This method is quite similar to the one you describe in the last part of your post.
The token generated by the server should be a value which cannot be forged: it cannot be a simple integer value incremented for each generated token, since a hacker could easily predict a valid value. It cannot be built using only information available to the client, for the same reason (although it would require more work for a hacker, he could ultimately forge a valid token). Also, on the server, the token should be attached with information allowing the server to easily and uniquely verify the token: a small variation in the connection information should result in the token being revoked. Token values should never be reused (with a token of finite length, there will still be a chance that a token value is reused, so figure out a length which is a good compromise between security and practicability). Finally, the token for a valid session should be regularly updated during the session, to prevent a malicious user steeling the session.
There are many ways to implement this, but the details depend on the security level you are trying to achieve. Using some sort of secret key to generate the token on the server is generally a bad idea, since there is always a chance that the key is leaked. The time when the token is generated may also be predictable. Pseudo-random number generators available to any programming languages have to be properly seeded so that the sequence of numbers cannot be predicted.
Finally, note that no authentication logic ever is completely safe: building more safety in your logic only makes the job harder to a hacker. Think about the incentive for a hacker to break into your system, and devise your logic so that the amount of work for breaking into the system is not worth the resource cost (time, money, specialty hardware…). And do never forget that obscurity does not mean security: let people review your process and comment on it, they may well think about some flaw that you had not seen.