I've been working with Socket.IO for a few days and it's been both extremely exciting and even more frustrating. The lack of current documentation/tutorials has made learning it very difficult. I finally managed to create a basic chat system, but there is one glaring question. How do I secure it?
What's stopping a malicious user from copying (or editing) my code and connecting to my server? I can grab the username from my PHP script and submit it to Socket.IO so I can recognize them as that user (and the PHP has security of course), but what's stopping someone from just submitting an unregistered username?
How can I make sure that the events submitted are authentic and haven't been tampered with?
My basic socket.io chat for references.
Server:
var io = require('socket.io').listen(8080);
var connectCounter = 0;
io.sockets.on('connection', function (socket) {
connectCounter++;
console.log('People online: ', connectCounter);
socket.on('set username', function(username) {
socket.set('username', username, function() {
console.log('Connect', username);
});
});
socket.on('emit_msg', function (msg) {
// Get the variable 'username'
socket.get('username', function (err, username) {
console.log('Chat message by', username);
io.sockets.volatile.emit( 'broadcast_msg' , username + ': ' + msg );
});
});
socket.on('disconnect', function() { connectCounter--; });
});
Client:
<?php session_start() ?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>untitled</title>
</head>
<body>
<input id='message' type='text'>
<div id="content"></div>
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
$.ajax({
type: 'GET',
url: 'https://mysite.com/execs/login.php?login_check=true',
dataType: 'json',
success: function(data) {
var username = data.username;
socket.emit('set username', username, function (data){
});
}
});
socket.on('broadcast_msg', function (data) {
console.log('Get broadcasted msg:', data);
var msg = '<li>' + data + '</li>';
$('#content').append(msg);
});
$('#message').keydown(function(e) {
if(e.keyCode == 13) {
e.stopPropagation();
var txt = $(this).val();
$(this).val('');
socket.emit('emit_msg', txt, function (data){
console.log('Emit Broadcast msg', data);
});
}
});
</script>
</body>
</html>
It all works dandy, except for having absolutely no security.
If you can install a key-value store like Redis on your node server, you can access it remotely from your php server using a Redis client like Predis. All you have to do is updating the remote session store on node server when a new login/logout happens in your php server.
Check this post for details: Authenticate user for socket.io/nodejs
The excellent passport framework for express uses secure cookies to validate identity. There is even a module to access it from socket.io.
Related
Can I connect to a nodejs server with socket.io from a button press? I got my page for example file:///home...site/index.html and a server running on my local machine for example localhost:8080. Can i connect to the server from my file with when i call a function, using xmlhttprequest or other means? How? Got links/tutorials?
I have a very simple socket.io example on GitHub: socketio-example
Update the index.html page in this example to look like this:
<!doctype html>
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script>
var socket;
function makeConnection() {
socket = io();
socket.on('welcome', function(data) {
addMessage(data.message);
// Respond with a message including this clients' id sent from the server
socket.emit('i am client', {data: 'foo!', id: data.id});
});
socket.on('polo', function(data) {
addMessage(data.message);
});
alert('connected.');
}
function addMessage(message) {
var text = document.createTextNode(message),
el = document.createElement('li'),
messages = document.getElementById('messages');
el.appendChild(text);
messages.appendChild(el);
}
function marco() {
socket.emit('marco');
}
</script>
</head>
<body>
<button onclick="makeConnection()">Connect</button>
<button onclick="marco()">Marco!</button>
<ul id='messages'></ul>
</body>
</html>
This will establish the socket.io connection when the user clicks Connect. Then you may click Marco! to send a message and receive the Polo! response.
This question has already been answered, but I can't understand it at all. You can find it at this link.
socket.on calls its callback too many times
I have the same problem as this fellow. I'm attempting to make a chat program with socket.io, but when more than one user joins, each message outputs the number of times of how many users have been connected.
For example, when one user is connected, and he submits a message. It outputs once. When two users are connected, each of their messages output twice.
When three users are connected, each of their messages output three times.
Here is my client side code:
$('document').ready(function() {
var server = io.connect('http://localhost:8888');
$('.chat').keydown(function(event){
var save = this;
if(event.which == 13){
server.emit('message', $(save).val());
$(save).val('');
return false;
}
});
server.on('incoming', function(message){
$('#textfield').append("<p>" + message + "</p>");
});
});
Here is my server side code:
var socket_io = require('socket.io').listen(8888).sockets;
socket_io.on('connection', function(socket){
socket.on('message', function(message){
socket_io.emit('incoming', message)
});
});
Thank you!
You can use socket.broadcast.emit() to send to everyone except that socket:
var io = require('socket.io')(8888);
io.on('connection', function(socket) {
socket.on('message', function(message) {
socket.broadcast.emit('incoming', message);
});
});
UPDATE: The following example works just fine for me:
server.js:
var app = require('http').createServer(handler);
var io = require('socket.io')(app);
var fs = require('fs');
app.listen(80);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.on('connection', function(socket) {
socket.on('message', function(message) {
socket.broadcast.emit('incoming', message);
});
});
index.html:
<html>
<head>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
$('document').ready(function() {
var server = io.connect('http://localhost');
$('.chat').keydown(function(event) {
if (event.which == 13) {
var $save = $(this);
server.emit('message', $save.val());
$save.val('');
return false;
}
});
server.on('incoming', function(message){
$('#textfield').append("<p>" + message + "</p>");
});
});
</script>
</head>
<body>
<input type="text" class="chat">
<div id="textfield"></div>
</body>
</html>
When pressing enter, the message in the input box is only displayed once to all other connected socket.io users.
Okay, I've finally figured out the problem.
I'm using Express 4.0. That means, I'm using routes to run the server, and I had the socket io code running inside the route. Each time a user connects, it has to go through the route first, and it's all binding onto the same socket_io.
Thanks to everybody who helped!
I also faced it, like multiple socket calls in network tab and i just add this "transports" key object to socket instance, both on client and backend.
socket = io("http://localhost:3002", {
transports: ['websocket']
})
React, Node, AWS EB
I'm totally new to node.js and I want to implement push notification system on a MySql database. I have a notification table in my database. In this table I have store recipient_id that specify the recipient of the notification. Now I want when a new notification with recipient_id is equal to current logged in user's id notify that user. Something like Stackoverflow If you are in the for example java tagged questions, every time a new question with java tag create, a notification appear on top of the page : 1 question with new activity.
Sorry for my poor English. Please help me to implement this system, because I'm new to it.
I have made a simple app like your requirement.
You can get help from following lines of code.You need to understand the basics of code. after that you will easily achieve your target. most of things from your requirement covered in this demo app.
Its not a exact but you will meet your target through this.
In this example a status post by any user will emit to all other users also at same time. we can manipulate it to achieve "1 new status".
make a table in database where your entries to be saved
CREATE TABLE status
(
`status_id` INT NOT NULL AUTO_INCREMENT,
`s_text` TEXT,
`t_status` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ( `status_id` )
);
//server.js
var app = require("express")();
var mysql = require("mysql");
var http = require('http').Server(app);
var io = require("socket.io")(http);
/* Creating POOL MySQL connection.*/
var pool = mysql.createPool({
connectionLimit: 100,
host: 'localhost',
user: 'root',
password: '',
database: 'fbstatus',
debug: false
});
app.get("/", function(req, res) {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket) {
console.log("A user is connected");
socket.on('status added', function(status) {
add_status(status, function(res) {
if (res) {
io.emit('new status', status);
} else {
io.emit('error');
}
});
});
});
var add_status = function(status, callback) {
pool.getConnection(function(err, connection) {
if (err) {
connection.release();
callback(false);
return;
}
connection.query("INSERT INTO `status` (`s_text`) VALUES ('" + status + "')", function(err, rows) {
connection.release();
if (!err) {
callback(true);
}
});
connection.on('error', function(err) {
callback(false);
return;
});
});
}
http.listen(3000, function() {
console.log("Listening on 3000");
});
//index.html
<html>
<head>
<title>Socket.io</title>
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src = "http://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script>
$(document).ready(function(){
var socket = io();
$("#add_status").click(function(){
socket.emit('status added',$("#comment").val());
});
socket.on('new status',function(msg){
var count = $('#count_status').text();
var valCount = parseInt(count);
if(valCount>=1) {
valCount = valCount+1;
} else {
valCount = 1;
}
var showMsg = '<div id="count_status"> '+valCount+' </div> new status';
$("#show_comments").html(showMsg);
});
});
</script>
</head>
<body>
<div id="comment_box" style = "padding:5%;">
<textarea id="comment" rows="5" cols="70"></textarea><br /><br />
<input type="button" id="add_status" value="Add">
</div>
<div id= "show_comments" class = "jumbotron"></div>
</body>
</html>
Run the app with following command
node Server.js
Now run http://localhost:3000/ in browser and to see the result open a new window in which you post a status and see your new status notification in both the window.
Thanks
Edited: This a great startup tutorial. a few thing needs modification.
connection.release() code ends up unreadable and not working. you should comets or remove it.
2.The actual output in my case:
You can do it 2 ways:
Query the server every n seconds for any new messages. Pass a timestamp of the last time you checked as a parameter and if any notification since the last check, return as json and display them in the client. This is called a pull strategy.
Or you can use websockets which maintains a permanent connection between your client and server, and then you can send notifications to the client from your server code in real-time. See socket.io tutorials. This is called a push strategy.
I want to send data via socket.io to my client via nodejs.
The data I am receiving are from pusher.
I am using an express backend and loading my server like that.
#!/usr/bin/env node
var debug = require('debug')('testApp');
var app = require('../app');
var Pusher = require('pusher-client');
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function () {
debug('Express server listening on port ' + server.address().port);
});
/**
* return pusher data
*/
var API_KEY = 'cb65d0a7a72cd94adf1f';
var pusher = new Pusher(API_KEY, {
encrypted: true
});
/**
* Socket.io
*/
var io = require("socket.io").listen(server, {log: true});
io.sockets.on("connection", function (socket) {
// This will run when a client is connected
// This is a listener to the signal "something"
socket.on("data", function (data) {
var channel = pusher.subscribe("ticker.160");
channel.bind("message", function (data) {
console.log(data);
});
});
// This is a signal emitter called "something else"
socket.emit("something else", {hello: "Hello, you are connected"});
});
On my client I am running the following script:
index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js" />
<script src='/javascripts/socket.js'></script>
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %> Juhu!</p>
</body>
</html>
My socket.js file:
var socket = io.connect(window.location.hostname);
socket.on('data', function(data) {
var total = data.total;
//print data to console
console.log(data);
});
My problem is that nothing gets shown in the console in my webbrowser, even though the data is coming in at my nodejs application.
Any recommendation what I am doing wrong?
I appreciate your replies!
I do believe the problem is when you use: socket.emit("something else", {hello: "Hello, you are connected"});
but have this in client-side: socket.on('data', function(data) {.
When you emit, you use the channel "something else", but on the client-side you are checking on the channel "data".
So on client-side you should be having socket.on('something else', function(data){.
Hope I helped. There isn't much info I could find on sockets.io, so I do not know if there is a preexisting channel called 'data'. Do enlighten me if so :)
I'm working on an applicatioin that I want to use with websocket interaction. I've used a node.js and socket.io based server and simple chat page as a starter for my page. I'm making modifications and figuring out the interactions between the server and html page.
The person who wrote the basic chat page used inline javascript on the html page as the client side of the chat, so I've broken that out into its own javascript file, no big deal there.
The issue is that I want to use the html and associated javascript file from the local machine, to connect to the node.js server I'm creating on the web-server. His setup was accessing the html page on the web-server in the same folder as the server.js file that acted as the web-socket server.
I'm trying to figure out how to get the client side javascript file to start doing it's thing when the page is opened (i'm guessing an on load event is needed), and how to set it up to call to the webserver javascript file.
I'm going to post his code here, it's not mine, I just used his tutorial to make the chat.html and server.js. Basically copy and paste.
Any help or guidance is greatly appreciated as always.
-----------------chat.html--------------------------
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Chat</title>
<script src="/socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
var URL = window.location.protocol + "//" + window.location.host;
console.log("Connecting to " + URL);
var socket = io.connect(URL);
// on connection to server, ask for user's name with an anonymous callback
socket.on('connect', function() {
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser', prompt("What's your name?"));
});
// listener, whenever the server emits 'updatechat', this updates the chat body
socket.on('updatechat', function(username, data) {
$('#conversation').append('<b>' + username + ':</b> ' + data + '<br>');
});
// listener, whenever the server emits 'updateusers', this updates the username list
socket.on('updateusers', function(data) {
$('#users').empty();
$.each(data, function(key, value) {
$('#users').append('<div>' + key + '</div>');
});
});
// on load of page
$(function() {
// when the client clicks SEND
$('#datasend').click(function() {
var message = $('#data').val();
$('#data').val('');
// tell server to execute 'sendchat' and send along one parameter
socket.emit('sendchat', message);
});
// when the client hits ENTER on their keyboard
$('#data').keypress(function(e) {
if (e.which == 13) {
$(this).blur();
$('#datasend').focus().click();
}
});
});
</script>
</head>
<body>
<h1>WebSocket Chat</h1>
<div style="float:left;width:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
<b>USERS</b>
<div id="users"></div>
</div>
<div style="float:left;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width:200px;" />
<input type="button" id="datasend" value="send" />
</div>
</body>
</html>
---------------------server.js-----------------------------
var port = 5000;
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
console.log("Listening on port " + port);
server.listen(port);
// routing
app.get('/', function (req, res) {
res.sendfile(__dirname + '/chat.html');
});
// usernames which are currently connected to the chat
var usernames = {};
io.sockets.on('connection', function (socket) {
// when the client emits 'sendchat', this listens and executes
socket.on('sendchat', function (data) {
// we tell the client to execute 'updatechat' with 2 parameter
io.sockets.emit('updatechat', socket.username, data);
});
// when the client emits 'adduser', this listens and executes
socket.on('adduser', function(username){
// we store the username in the socket session for this client
socket.username = username;
// add the client's username to the global list
usernames[username] = username;
// echo to client they've connected
socket.emit('updatechat', 'SERVER', 'you have connected');
// echo globally (all clients) that a person has connected
socket.broadcast.emit('updatechat', 'SERVER', username + ' has connected');
// update the list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
});
// when the user disconnects.. perform this
socket.on('disconnect', function(){
// remove the username from global usernames list
delete usernames[socket.username];
// update list of users in chat, client-side
io.sockets.emit('updateusers', usernames);
// echo globally that this client has left
socket.broadcast.emit('updatechat', 'SERVER', socket.username + ' has disconnected');
});
});