prevent unique user api tokens from being generated - javascript

I'm currently developing a login API for use across two different platforms. It's pretty straightforward, simply comparing an email and hashed password in the database and returning a unique token (stored as a cookie) for future data retrieval.
It works perfectly at the moment. However, any malicious user could abuse this system by visiting the API endpoint and constantly logging in, generating an infinite amount of tokens in the database.
So, what is the best approach to preventing something like this? The only solution I could develop is a unique device identifier. Still, browsers heavily restrict that information and an attacker could always spoof the data.
Here's my current logic in PHP (note that this is simplified and actually returns a JSON object):
/* /api/handle/login.php */
$email = Input::post("auth_email") ?? "";
$password = Input::post("auth_pass") ?? "";
$user = new User;
$user->login($email, $password);
// Check that the user credentials are correct.
if(!$user->loggedIn()){
echo "Failed to login.";
}
// Retrieves an authentication generated on $user->loggedIn().
echo $user->authToken();
Now I cannot generate only one token per user, as this would mean they would be signed out every time they sign in on a new device. Same thing for IP identification.

Related

What can be changed by user on web? (eg. $_SESSION, JS code)

I would like to know what can and what can not be changed by user related to Web Development.
Mainly if users can change variables in $_SESSION.
But it would be nice to know if some techniques that seem secure are actually not.
Another example would be user changing code in JS Classes etc.
I am sorry if this question seems too trivial to someone. Studied Web Development for 2 years and would like to learn something new.
Here is a example of code where I am not sure if user can change his $_SESSION['group']
public function login() {
if(isset($_POST['login_submit'])) {
if(isset($_POST['username']) and isset($_POST['password'])) {
// Fetching user data
$stmt = $this->conn->prepare('SELECT Password FROM TB_Users WHERE Username = ?');
$stmt->execute([$_POST['username']]);
$user = $stmt->fetch();
//-----------------------
// Password Verification
if(password_verify($_POST['password'], $user['Password'])) {
//-----------------------
// Fetching Group of user so it can be used later to fetch Permissions
$stmt = $this->conn->prepare('SELECT TB_userGroups_ID FROM TB_Users WHERE Username = ?');
$stmt->execute([$_POST['username']]);
$UserGroup = $stmt->fetch();
$_SESSION['group'] = $UserGroup['TB_userGroups_ID'];
//-----------------------
// Sending user back from Login page to Main/Index page
header("Location: ../index.php");
exit();
//-----------------------
}
}
}
Many thanks for any help or redirection to sources.
If by user you mean visitors to the website and not developers (just making sure), then no they cannot unilaterally change anything in $_SESSION since those values only exist on the server. The user only has a cookie on their end that the server uses to recognize which collection of $_SESSION variables belong to them. The developer is responsible for making sure that what goes into the $_SESSION is controlled. In the example you have here, the only way $_SESSION gets changed is based on what is retrieved from the database, so assuming that content is safe, then it is protected.
My only recommendation would be to get rid of your isset($_POST['var']) stuff and replace it with filter_input(). You can use this to retrieve values from $_POST and also sanitize them. When called, you can expect null or false for missing or invalid content, so it's a little easier to control validation vs empty values. Sample:
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
Full docs on that here https://www.php.net/manual/en/function.filter-input.php
Be sure to familiarize yourself with the filter flags. FILTER_SANITIZE_STRING for instance is not a great one for passwords.
Some other things to consider:
Make sure your session cookies are flagged with HTTPOnly and Secure and if on PHP7+ also set SameSite flag to strict. HTTPOnly prevents javascript from being able to modify the cookie. These settings are in php.ini.
Make sure your users are protected from XSS where someone could access their session through malicious code injected into your site (or perhaps a completely external site). These headers can be set in an .htaccess or in a host/vhost configuration file.
Ensure that your encryption policy for passwords meets basic requirements including secure encryption methods and salts. In general you shouldn't have to retrieve a password from the database; you should be able to salt and encrypt the provided password one way and change your query to simply count the number of rows matching username and the encrypted password. This way the secured password in the database never exists on the web server (even in memory).

REST API web security without multiple users

I never built a REST API, so,
My idea is: I have an SQL database that has a table with name and description (for this example it is car name and its description is somewhat simple) I want to create a REST API, and thus be able to consume it in any future application. I thought I would do it in php, now my question is for me to be able to access this rest api I must access using url and this will return the results in json form. But as it is done so that only my website can use it (in this example I am developing it in reactjs) and not any other that does not have authorization. I know something about JWT, but I do not know if it is indicated, this web page has no users, it only serves for you to see these "products", I read something about oauth 2.0, I do not know if this is what I am thinking of.
https://blog.restcase.com/4-most-used-rest-api-authentication-methods/
Basic Authentication is probably the easiest. Just google PHP Basic Authentication REST API implementation
There's a very basic old example on php.net in the comments https://www.php.net/manual/en/features.http-auth.php
<?php
$valid_passwords = array ("mario" => "carbonell");
$valid_users = array_keys($valid_passwords);
$user = $_SERVER['PHP_AUTH_USER'];
$pass = $_SERVER['PHP_AUTH_PW'];
$validated = (in_array($user, $valid_users)) && ($pass == $valid_passwords[$user]);
if (!$validated) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
die ("Not authorized");
}
// If arrives here, is a valid user.
echo "<p>Welcome $user.</p>";
echo "<p>Congratulation, you are into the system.</p>";
?>
But the above is not using a database to store user login/hashed password, it's just storing it in an array. But it would be very quick to prototype your authentication before making something a bit more complicated
Here's another basic example along the same lines
https://gist.github.com/rchrd2/c94eb4701da57ce9a0ad4d2b00794131
So with this setup, if you're sending a GET request to your REST API endpoints to get the json, you would also need to include the username/pass in the Http request headers otherwise you would get the 401 not authorized response instead of the JSON.
See the answer here for how you would code the GET request from your PHP to call the REST endpoint
How do I make a request using HTTP basic authentication with PHP curl? or here also has a good example PHP: how to make a GET request with HTTP-Basic authentication

Web security for a new company - Am I doing this right?

I've been working on a social media management tool company for the last eight months. This will be the first major website I release and I have concerns about its security and systems. Obviously security must be a very high priority as my target customers are businesses and individuals who are looking to grow their social followings. If my company's site gets hacked and any of my client's profiles get accessed it would destroy any reputation I had built up and massively slow down progression of the company. So today I'm wanting to share with you all how I wrote the site and see if there are any security flaws I could run into, or if there's a better way to write any of the systems I have in place.
Server systems (Java side of things)
When I first started working on this company I mainly knew Java as I worked with it in a few previous jobs. While other languages may be similar and more powerful, such as C++, I decided to stick to what I knew best. I felt like I still made the correct choice when I was 30,000+ lines in as my servers were running with every little CPU usage and only using 11% - 24% of it's allocated 64MBs of memory. Figured switching at any point to C++ or similar wouldn't be worth the time for such little possible performance improvement.
I have a server running for each social profile. If a client has an account with a Facebook page and two Twitter accounts there will be three servers running for that client. Each one will load specific modules of my software depending on the social platform (Facebook vs Twitter etc). The reason why I wanted one server per social profile is that some payment plans could add more and more social profiles. With more and more social profiles I'd need more and more resources to run that server. I'd rather have the minimum assigned to each social profile server than have to constantly adjust the performance of one large server for a client with 13 social profiles (as an example). Another benefit is to be able to easily remove social profiles, or to "overflow" servers to another box if my current box becomes full and a client request another social profile server. If I would need to expand a large server due to increase request in social profiles on an already full box that may become messy. Is this wrong to do? Is there any flaws in my logic here?
These servers will handle the jobs of post scheduling, listening for "social events" (new followers, direct messages etc) and reacting accordingly to them based on my site's features.
Account registration
I have the typical registration system with an email, a password and a confirm password. I currently don't have a confirm email system but of course that'll be added before launch. Would having a "remember me" option open up any security flaws? If so what ones and what actions could I take to prevent them?
My current system doesn't use MySQL in PHP at all. I use socket communication to send the information to my Java servers to create an account in my MySQL database. There's a Java server used just for "general" communication that isn't meant to be for a specific social profile. The main reason for wanting to create an account on the Java side instead of in PHP is that once I add iOS and Android apps I can easily sent the same sockets to create an account within the app. Would sending sockets to communicate to a Java server to run the MySQL query cause any problems?
What is the absolute most correct and secure way to handle account registration?
Server to browser communication
I am using AJAX to communicate with a PHP script that uses sockets to communicate with my Java servers. Here's a basic example of an AJAX call:
$(document).on("click", ".trash", function() {
//TODO: Add a "are you sure" pop up
var element = $(this).closest(".scheduleddata");
var socialCount = element.attr("socialcount");
var botIndex = element.attr("botid");
element.css("display", "none");
element.html("");
$.ajax({
url: "/client.php",
type: "POST",
dataType: "JSON",
data: {
packet: "62:" + botIndex,
socialCount: socialCount
},
timeout: 15000,
async: true
});
});
Packet ID "62" is meant to delete a scheduled post. Each bot index is a completely unique identifier for each scheduled post. The social count is a counter for each social profile attached to that client's account. For example if I have four social profiles linked to my account I could communicate with a server that has a social count of 1 - 4. If a friend of mine makes an account and links two social profiles to their account, they can communicate with social counts 1 - 2. So the social count is only unique to each client's account. It could be completely possible to make the social counts completely unique. Using the previous example I'd have access to social counts 1 - 4 and my friend would have 5 - 6. Would that be a more ideal system to prevent possible attackers from knowing that social count #1 would always exist?
There is a client/account ID as well, as expected it is the auto incrementing integer in the accounts MySQL table. I used to require the client ID to be sent in the data of the AJAX calls but then I learned that anyone could then communicate with any servers on my service through AJAX and that's obviously not good at all. Currently I have the client ID stored in a PHP session variable when they login. So because I have the first account ever created on the site my client ID is 1, a friend of mine who is helping me test is 2, etc. The client ID is never displayed, loaded, stored, or used anywhere but the session variable. Is there any security flaws to this? If someone could edit that variable and sent the right packets they could communicate with other client's social profiles and that's not good obviously.
For my client.php code I load the address and port of the targeted server:
<?php
if(isset($_POST['packet']) && isset($_POST['socialCount'])) {
$socialCount = $_POST['socialCount'];
if($socialCount > 0) {
echo json_encode(client::send(strip_tags($_POST['packet']), null, -1, $socialCount));
}
}
class client {
public static function send($message, $address, $clientID, $socialCount) {
if(!isset($_SESSION)) {
session_start();
}
$message = strip_tags($message);
if($clientID == -1) {
$clientID = 0;
if(isset($_SESSION['client_id'])) {
$clientID = $_SESSION['client_id'];
} else {
return null;
}
}
$message .= "\n";
$port = 3000;
if(isset($_SESSION["location"][$clientID][$socialCount])) {
$location = explode(":", $_SESSION["location"][$clientID][$socialCount]);
$address = $location[0];
$port = $location[1];
} else {
if($address == null) {
if($clientID == 0 || $socialCount == 0) {
$address = "localhost";
} else {
$reply = client::send("14:" . $clientID . ":" . $socialCount, "localhost", 0, 0);
if(strcmp($reply, "-1") == 0) {
$address = "localhost";
} else {
$result = explode(':', $reply);
$address = $result[0];
$port = $result[1];
}
}
}
$_SESSION["location"][$clientID][$socialCount] = $address . ":" . $port;
}
$socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
try {
socket_connect($socket, $address, $port);
$message = utf8_encode($message);
$status = socket_sendto($socket, $message, strlen($message), MSG_EOF, $address, $port);
if($status != false && $next = utf8_decode(socket_read($socket, $port))) {
return substr($next, 2);
}
} catch(Exception $e) {
}
return null;
}
}
?>
I feel like most of this code could be improved, I wrote it when I first started learning PHP so please excuse any sloppyness. I am currently storing the returned address:port into a session variable so I only have to load it once. There are some parts of the company that send packets to external servers that my clients set up. So the address/port of their social profile would be public information anyways. I'm blocking incoming communication from IP addresses that are not "whitelisted". These "whitelisted" IPs will be all of my own boxes for now. So I will just be sending packets and not receiving them ideally. Are there any problems with this system?
On a side note, I believe the way Java and PHP encode unicode is different. Whenever I encode unicode and send it from the Java server to the PHP server and I decode it, it doesn't work. How could I fix this problem? I've been having problems figuring this one out for months.
Security measures already in place
As you saw above I'm already using strip_tags and removing all things I can from AJAX calls. I am also buying a standard SSL from GoDaddy, and I'll be upgrading to their most powerful SSL plan once the company starts turning a decent profit.
What are some other basic security that I should be implementing into my site?
Conclusion
As you can see for the type of company I'm trying to launch it seems that security is very important. I'd absolutely love to hear any input and advice anyone has. Thank you to anyone who spent the time to read the full post!

Vaildate user by label value

I am validating my users with header variables that I display in my .net application and my question is how can I validate that the user that is on the on the current page is allowed to proceed to any other pages.
I want to check the name from an array or names and if they are not listen then it will redirect them to an error page letting them know they do not have access.
I was going to take the path of sql authentication but that would just require an additional login page and since I already check the header variables I thought I could just go about this way. Any help regarding this would be great!
You should never trust ANY data sent from the client to your server. The header-variables can easily be modified to represent anything. One could easily forge the header to spoof themself for being somebody else (like admin in worst case).
You should really consider some sort of authentication that requires a combination of username + password, I'm afraid.
If you REALLY want to rely on the headers though, add a header that identifies themself, like X-USERNAME:CSharpDev4Evr, and then just parse that one and match against the array on back-end.
I don't know any C#.NET, but here's a JavaScript-snippet showing the principle:
var headerUsername = "CSharpDev4Evr";
var validUsernames = ["Eric", "CSharpDev4Evr", "Stackoverflow", "root"];
// Check if we are in the array
// Re-direct if we're not
if (validUsernames.indexOf(headerUsername) === -1)
window.location = 'error.html';
// Proceed with other authenticated stuff here
// ...

Will using the same database for client hashes, salts, and settings expose client hashes?

If I have an XML database on my web server;
<Database>
<Client sid="0123456789abcdefg" name="John Doe" email="johndoe#mail.com" hash="9876543210abcdefg" salt="abcdefg9876543210">
<Setting>A Setting</Setting>
<Setting>Another Setting</Setting>
</Client>
...
</Database>
And I log in with the hash and salt, retrieve the SID, and redirect to the home page via PHP;
header("Location: home.html?sid=" . $sid);
And then use the SID in the location bar via JavaScript to retrieve the user settings from the same database, will I expose my clients' hash?
Is there a better way, or a more standard way, to set and get user settings on the web?
P.S.: Unless you have a really good reason, I really, really, really, don't want to use SQL. I prefer to be able to read my databases, and I like the tangibility and versatility of XML.
Edit: After a little more research, I learned that PHP supports a system for storing SESSION[] variables. This is perfect for me because I am, in fact, using sessions!
The W3C says:
"A PHP session variable is used to store information about, or change settings for a user session. Session variables hold information about one single user, and are available to all pages in one application."
Much better than exposing various data in the address bar. =)
As long as your DB file is inaccessable from HTTP (i.e. locked by a .htaccess or equivalent) and other protocols (i.e. not sitting in a directory accesable by anonymous FTP), the only risk is to (inadvertently) let the hash&salt be collected among a bunch of other user-related data and sent to your clients.
If you have requests equivalent to the SQL * selector, that might be somewhat of a problem. You might want to put the critical data into a different DB file and encapsulate the accesses in an interface dedicated to user registration and login, just to make sure no other piece of code will be able to grab them (even by mistake) from your main DB.

Categories