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

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!

Related

prevent unique user api tokens from being generated

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.

I am trying to manage a small number of users control of a webpage

So to start off, I have a raspberry pi, running a lighttp server on arch. I have a webpage that will have a max of 10 people connected at a time. Each user will be given the tag "Master," or "observer." The webpage will have controls that only the "Master," can use.
Just a heads up: I am just learning most of this so I may be making some mistakes about how to accomplish this.
My original idea is has follows. When a user connects to the database their IP address would be grabbed and inserted into a SQLite database, along with a user tag, and time of connection. From there I would be able to query the database for the users tag when they tried to execute various commands.
Whatever I use needs to be very lightweight and not store cookies on the users device.
Here is the JavaScript I currently have, it probably isn't the most efficient, but I plan on getting it working then making it look nice.
This code is supposed to connect the databases and insert the user.
<script type="text/javascript" src="http://l2.io/ip.js?var=myip"></script>
<script type="application/javascript">
var db = openDatabase('userCon.contbl.sqlite', '1.0', 'contbl', 1024);
db.transaction(function(transaction) {
var ip = myip;
var conStatus = "master"
var date = new Date();
console.log('Inserting into the database ' + ip + ',' + conStatus +',' + date);
transaction.executeSql('INSERT INTO contbl(ipAd, conType, lastActive) VALUES (?,?,?,?)',[ip,conStatus,date], function(transaction, results) {
}, function (transaction, err){
console.log(err.message+":Error"); // here an error
});
});
</script>
<script type="application/javascript" src="http://jsonip.appspot.com/?callback=getip"> </script>
I am unable to connect to the SQLite database I created on the pi, which after my research may be because SQLite is supposed to be run locally and not on a server.
Is there some sort of work around to point to the SQLite database on the pi, or is there a better resource to use for this type of task?
EDIT:
I guess my original post was not specific enough. The basic idea is I need to be able to pass a tiny bit of information from a webpage, back to the server hosting it. i.e. User connect to the server and sends its IP then the server tags that IP as an Observer of Controller. From there the server will treat each person viewing the webpage differently based on how the user was tagged.
My original plan was to use a really light weight database like SQLite, but as I found out, SQLite is local use only. I need to do this on a sever with lower then 10 connections.
My hope is someone has a suggestion, or an example to solve this problem.
The most common way for javascript running on a web page to talk to a server these days is some kind of RESTful web service.
You'll want to find a server-side programming language that runs on the Pi. Maybe node.js? It's like javascript but on a server, see here: http://weworkweplay.com/play/raspberry-pi-nodejs/
You then write whatever methods you want in the server-side language, methods which talk to the database, then have your client-side javascript call those methods. Google "REST services node.js" and you'll find plenty of how-tos.
If the SQLite database is running on the server, and this code runs in the user's browser, it can't connect to the database. The only interaction between the browser and your server is HTTP, unless there's a gigantic security hole in your server.

Cross site file upload with php authentication

I have two domain names (in two hosting locations). Domain 1 is a normal website with authentication. I am using Domain 2 as a place to just upload files (for storage). I am using angular-file-upload https://github.com/danialfarid/angular-file-upload from client side.
My backend code is super simple and it is current working .. but without any form of authentication.
<?php
header('Access-Control-Allow-Origin: *');
$fname = $_POST["fname"];
if(isset($_FILES['file'])){
//The error validation could be done on the javascript client side.
$errors= array();
$file_name = $_FILES['file']['name'];
$file_size =$_FILES['file']['size'];
$file_tmp =$_FILES['file']['tmp_name'];
$file_type=$_FILES['file']['type'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
$extensions = array("jpeg","jpg","png", "gif");
if(in_array($file_ext,$extensions ) === false){
$errors[]="image extension not allowed, please choose a JPEG or PNG file.";
}
if($file_size > 2097152){
$errors[]='File size cannot exceed 2 MB';
}
if(empty($errors)==true){
move_uploaded_file($file_tmp,"images/".$file_name);
echo $fname . " uploaded file: " . "images/" . $file_name;
}else{
print_r($errors);
}
}
?>
Questions:
How to make sure the user is authenticated in Domain 1 before they can upload files? I mean I could just change Access-Control-Allow-Origin but someone can easily go to Chrome Developer and do a POST upload from custom javascript.
Is there a way to do #1 without getting overly complicated? Is it possible to pass some cookie values?
I have full control of both hosting sites so I can do whatever I want.
Sharing a common secret
One way is to share a secret, wich is only known to Site A and Site B.
Suppose Site A and Site B know a common complex and non-predictable string salt [randomness source].
If Site A authenticates a user, A creates a random string rndA, a valueThrough timestamp and then computes a hash like so:
sharedHash = hash( rndA + salt + valueThrough )
Site A hands over this tuple to the client: [ sharedHash, valueThrough , randA ]
The clients hands over this tuple to Site B
Site B then verifies the client's rights using the same hash() operation.
If B computes the same sharedHash and the current timestamp is still smaller than valueThrough, client gets authenticated.
Letting Site A and Site B talk to each other
Alternatively, Site A and Site B might talk directly to each other:
Site A hands over a security token to the client
Client hands over the security token to Site B
Site B then verifies the token by directly talking to Site A
While this technique requires reachability of Site A <-> Site B, the former technique even works, if Site A and Site B can't exchange HTTP-requests directly.
In both cases Generating cryptographically secure tokens might be of interest.
Other and stronger techniques certainly exist.
How's about sharing session in db like redis or mongodb?

Close server-side chat connections before unload in javascript

On my website, I have built a chatroom with support for multiple rooms. When a user joins the room, a session is placed into the database so that if they try to join the room again in another browser window, they are locked out.
It works like this
1. Join the chatroom page
2. Connect to chatroom #main
If the user has a session in the database for #main
--- Block user from joining
else
--- Load chatroom
When the chatroom is closed client side or the user terminates there connection with the /quit command, all of their sessions are deleted, and this works fine.
However
There is a possibility that users will just close the browser window rather than terminating their connection. The problem with this is that their session will stay in the database, meaning when they try to connect to the room, they are blocked.
I'm using this code onbeforeunload to try and prevent that
function disconnect() {
$.ajax({
url: "/remove-chat-sessions.php?global",
async: false
});
};
This is also the function called when the user types the /quit command
The problem
The problem with this is that when I reload the page, 5 times out of 10 the sessions have not been taken out of the database, as if the ajax request failed or the page reloaded before it could finish. This means that when I go back into the chatroom, the database still thinks that I am connected, and blocks me from entering the chatroom
Is there a better way to make sure that this AJAX call will load and if not, is there a better alternative than storing user sessions in an online database?
Edit:
The reason users are blocked from joining rooms more than once is because messages you post do not appear to you when the chatroom updates for new messages. They are appended to the chatroom box when you post them. This means that if users could be in the same chatroom over multiple windows, they would not be able to see the comments that they posted across all of the windows.
In this situation you could add some sort of polling. Basically, you request with javascript a page every X time. That page adds the user session to the database. Then there's a script executing every Y time, where Y > X, that cleans old sessions.
The script that is called every X time
...
// DB call (do as you like)
$All = fetch_all_recent();
foreach ($All as $Session)
{
if ($Session['time'] < time() - $y)
{
delete_session($Session['id']);
}
}
The script that javascript is calling every X time
...
delete_old_session($User->id);
add_user_session($User->id, $Chat->id, time());
The main disadvantage of this method is the increment in requests, something Apache is not so used to (for large request number). There are two non-exclusive alternatives for this, which involve access to the server, are:
Use nginx server. I have no experience in this but I've read it supports many more connections than Apache.
Use some modern form of persistent connection, like socket.io. However, it uses node.js, which can be good or bad, depending on your business.

long polling - jquery + php

I want to long poll a script on my server from within a phonegap app, to check for things like service messages, offers etc.
I'm using this technique in the js:
(function poll(){
$.ajax({
url: "/php/notify.php",
success: function(results){
//do stuff here
},
dataType: 'json',
complete: poll,
timeout: 30000,
});
})();
which will start a new poll every 5 minutes (will be stopping the polling when the app is 'paused' to avoid extra load)
I am not sure how to set up the php though? I can set it up so it doesnt return anything and just loops trough the script, but how to make it return a response as soon as i decide i want to send a message to the app? my php code so far is:
<?php
include 'message.php';
$counter = 1;
while($counter > 0){
//if the data variable exists (from the included file) then send the message back to the app
if($message != ''){
// Break out of while loop if we have data
break;
}
}
//if we get here weve broken out the while loop, so we have a message, but make sure
if($message != ''){
// Send data back
print(json_encode($message));
}
?>
message.php contains a $message variable (array), which normally is blank however would contain data when i want it to. The problem is, when i update the $message var in message.php, it doesnt send a response back to the app, instead it waits until it has timed out and the poll() function starts again.
so my question is, how do i set-up the php so i can update the message on my server and it be sent out instantly to anyone polling?
Long polling is actually very resource intensive for what it achieves
The problem you have is that it's constantly opening a connection every second, which in my opinion is highly inefficient. For your situation, there are two ways to achieve what you need; the preferred way being to use web sockets (I'll explain both):
Server Sent Events
To avoid your inefficient Ajax timeout code, you may want to look into Server Sent Events, an HTML5 technology designed to handle "long-polling" for you. Here's how it works:
In JS:
var source = new EventSource("/php/notify.php");
source.onmessage=function(event) {
document.getElementById("result").innerHTML+=event.data + "<br>";
};
In PHP:
You can send notifications & messages using the SSE API interface. I
don't have any code at hand, but if you want me to create an example,
I'll update this answer with it
This will cause Javascript to long-poll the endpoint (your PHP file) every second, listening for updates which have been sent by the server. Somewhat inefficient, but it works
WebSockets
Websockets are another ballgame completely, and are really great
Long-Polling & SSE's work by constantly opening new requests to the server, "listening" for any information that is generated. The problem is that this is very resource-intensive, and consequently, quite inefficient. The way around this is to open a single sustained connection called a web socket
StackOverflow, Facebook & all the other "real-time" functionality you enjoy on these services is handled with Web Sockets, and they work in exactly the same way as SSE's -- they open a connection in Javascript & listen to any updates coming from the server
Although we've never hard-coded any websocket technology, it's by far recommended you use one of the third-party socket services (for reliability & extensibility). Our favourite is Pusher

Categories