This is a challenge I am facing in Reactjs, though I don't believe that it is necessarily attributed to it. I am trying to make an API call in React. And while it works, the code also reveals my API key, which below is indicated by my javascript variable sting. When I preview the code in my browser, sting quite clearly shows my API key.
render: function() {
if (this.state.trial) {
return this.iftroo();
}
}
});
var Troo = React.createClass({
render: function() {
var sting = "<?php
$con = mysqli_connect('localhost', 'root', '', 'worldly') or die("Trying");
$query = "select * from testi";
$result = mysqli_query($con, $query);
while($row = mysqli_fetch_array($result)){
echo $row["userName"];}
?>";
var weather = new XMLHttpRequest();
weather.open("GET", "http://api.openweathermap.org/data/2.5/weather?q=London,uk&units=imperial&appid="+sting, false);
weather.send(null);
var r = JSON.parse(weather.response);
var tempurature = r.main.temp;
return (
<p>
{tempurature}
</p>
I understand that in order to get this to work, I will likely have to embed my javascript code inside my PHP. However, doing so leads to errors, such as PHP not recognizing javascript var characters.
What measures can I take to hide my API keys from the browser?
If you want to hide the API key from the browser then you must simply never give it to the browser.
You can't use the API key from client side JavaScript and keep it hidden from the client.
Make any HTTP request that needs to use it from your server (e.g. using PHP's cURL library).
You could generate one-time jwt api keys, for a special user, with expiration time, and what ever information assigned it.
edit
OK, now I see, that the api key is for an external service. Don't know how the policy for the weather service is, but.. I think this is not the right way to go, you should make this request on the server.
Related
I have a basic chat system set up that uses an SQL database and a PHP script -- when the user inputs a message, its sent to the database and then is retrieved and displayed. New messages are displayed every 5 seconds regardless.
All that being said, its fairly easy to just spam messages causing the website to stop responding at which point clicking any links will result in an error page, and no further messages will be input.
Is this a common scenario? How should I improve the chat's performance? Note: I'm really new PHP and JS/Jquery.
Here is the main script that is frequently called to update the html chatbox with new messages for the logged-in user:
Two auto-incremented values are compared to determine "new messages", the value of the last displayed message, and the value of the last message in the database.
<?php
session_start();
if (isset($_SESSION['logged_in']) && $_SESSION['logged_in'] == true) {
$alias = $_SESSION['username'];
$host = 'localhost';
$user = 'root';
$pass = '';
$database = 'vethergen_db_accounts';
$table = 'table_messages';
$user_table = 'table_user_info';
$last_id_table = 'table_chat_sync';
$connection = mysqli_connect($host, $user, $pass) or die ("Unable to connect!");
mysqli_select_db($connection,$database) or die ("Unable to select database!");
if ($redis->exists("/lastId/$alias"))
{
$last_id = $redis->get("/lastId/$alias"); //Gets the last id from cache...
}
else
{
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
$last_id_result = mysqli_query($connection,$last_id_query);
$last_id_rows = mysqli_fetch_array($last_id_result);
$last_id = $last_id_rows['last_id'];
// Now that you just read it, create a last_id cache entry for this user
$redis->set("/lastId/$alias", $last_id);
}
$query = "SELECT * FROM $table WHERE text_id > '$last_id'"; //SELECT NEW MESSAGES
$result = mysqli_query($connection,$query);
if ($result && mysqli_num_rows($result) > 0)
{
while($row = mysqli_fetch_array($result))
{
$color_alias = $row['alias'];
$text_color_query = "SELECT color FROM $user_table WHERE alias = '$color_alias'";
$text_color_result = mysqli_query($connection,$text_color_query);
$text_color_rows = mysqli_fetch_array($text_color_result);
$text_color = $text_color_rows['color'];
if ($row['alias'] === "Vether")
{
echo '<p id = "chat_text" style="color:'.$text_color.'">'.'<b>'.$row['alias'].': '.'</b>'.$row['text']."</p>";
echo '<p id = "time_stamp">'.$row['time'].'</p>';
echo '<p id = "chat_number">'.$row['text_id'].'</p>';
}
else
{
echo '<p id = "chat_text" style="color:'.$text_color.'">'.'<b class = "bold_green">'.$row['alias'].': '.'</b>'.$row['text']."</p>";
echo '<p id = "time_stamp">'.$row['time'].'</p>';
echo '<p id = "chat_number">'.$row['text_id'].'</p>';
}
echo '<hr class = "chat_line"></hr>';
$last_row_id = $row['text_id'];
}
//UPDATE LAST SYNC ID
$update_query = "UPDATE $last_id_table SET last_id = '$last_row_id' WHERE alias = '$alias'";
$redis->delete("/lastId/$alias");
mysqli_query($connection,$update_query);
}
else {echo '';}
?>
There is no specific right answer because your question is very general, but there are a few things that are obvious here. You have built a botteneck in your database where the more users you have, the more updates you are doing on the table_chat_sync.
As an aside, I have no idea why you are putting a constant (the table name) into PHP variables for your queries. At very least these should be php constants but that makes the syntax pretty painful. Your code is simpler and better just using the table names in the SQL.
InnoDB
Are you using InnoDB tables? You should be, given that you are updating a row and with InnoDB you have row level locking.
You also want to make sure that you have enough innodb buffer pool cache allocated to insure that the db is in memory. This will buffer your select activity a lot and buy you some head room.
MySQL EXPLAIN
You also need to do explain plans on your select query and insure that it is properly indexed so that the queries are being returned using indexes and you are not table scanning or having temporary tables created.
SQL queries against mysql are quite slow compared to getting data from cache, and the reality is that the full set of chat messages doesn't change much, and yet your system is repeatedly going to be querying the chat or a subset of it over and over again. For this reason, most sophisticated systems are using some sort of caching system or queuing. There is overlap between these two technologies and they tend to offer better scalability as well as support for concepts like publish/subscribe that fit chat very well.
Redis & Other backends
Redis as an example, could be the back end for chat and completely supplant the actual storage and retrieval of messages. The document database MongoDB is also an alternative option that has in-memory characteristics when the dataset can be controlled.
Using Redis with MySQL
Redis is often combined with an RDBMS and in your code there are a few places where it could be a great help. For example, you do this query repeatedly:
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
With redis you could do something like this:
if ($redis->exists("/lastId/$alias")) {
$last_id = $redis->get("/lastId/$alias");
} else {
$last_id_query = "SELECT last_id FROM $last_id_table WHERE alias = '$alias'";
$last_id_result = mysqli_query($connection,$last_id_query);
$last_id_rows = mysqli_fetch_array($last_id_result);
$last_id = $last_id_rows['last_id'];
// Now that you just read it, create a last_id cache entry for this user
$redis->set("/lastId/$alias", $last_id);
}
The only other detail is that when you update the last Id you would want to delete the redis key:
$redis->delete("/lastId/$alias");
Hopefully you can see that this would lower the load on mysql quite a bit, because no query will occur without a new message being added. This will buffer mysql quite a bit, and the same concept can be used to cache the other queries you are doing, such that you never require mysql queries unless you have a new user actively using Redis. I didn't go into this but you can set the expiration of a key to some period of time, so it will clean up old keys from non-active users.
Load Testing to understand your bottlenecks and capacity
Your choice of reliance on MySQL is something you will have to accept as limiting, although again you may be able to tune it so that within your use case and load, it runs acceptably, but that is impossible to predict without detailed configuration analysis and load testing. There are many load testing and stress testing tools that are FOSS, with Apache JMeter being one of the oldest ones, so I'll advise you to start with that.
Websockets
Last but not least, polling is inherently wasteful and most chat systems these days are built using websockets which is just a better fit for the task of having a sustained client-server connection. Websocket is client & Server code, and being that you are a PHP dev, there are a few projects that can help you out here, Ratchet being one that has been around for a while. There's a PHP client lib Pawl that shows you how to make a simple robust websocket connection.
You can add a Limit to the end of SELECT * FROM $table WHERE text_id > '$last_id' and that will keep some of the spam messages from slowing down the thread. Also you can prohibit duplicates on the INSERT statement.
I'm brand-new to SSE. There are plenty of simple/introductory texts on server sent events
Here
Here
Here
But none of them touch on using the same SSE file for multiple different users.
For example:
I have a site, where users log on. While logged on, they can view data that is unique and private to them. I'd like each user to have live updates while they are logged in, which may or may-not contain sensitive information. To do so I am implementing server-sent events:
JS (Straight out of one of the links)
var source;
if (!!window.EventSource) {
source = new EventSource("sse.php");
} else {
...
}
source.addEventListener("message", function(e) {
... do stuff ...
}, false);
PHP
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");
while (true) {
$data = \\ query DB or any other source
if ($data) {
sendMessage($someID, $data);
}
sleep(2);
}
function sendMessage($id, $data) {
echo "id: $id\n";
echo "data: $data\n\n";
ob_flush();
flush();
}
But using it this way, am I only sending the data to the user who opened the sse.php source (i.e. each EventSource("sse.php") is a new, unique connection)? Or will everyone logged on, who has initialized the connection, receive the same data?
This SO answer touches on multiple users, by using unique events:
echo "event: ping\n";
$msg1="This is first user";
echo 'data: {"msg": "' . $msg1 . '"}';
echo "\n\n";
echo "event: notify\n";
$msg2="This is second user";
echo 'data: {"msg": "' . $msg2 . '"}';
echo "\n\n";
And then only listening for a certain event:
var evtSource = new EventSource("sender.php");
evtSource.addEventListener("ping", function(e) {
var obj = JSON.parse(e.data);
var r_msg = obj.msg;
But that hardly seems reasonable. If each user is supposed to be receiving their own private feed, then this method would require me to hard-code a unique event for each user. AND, as the original answer mentions, it does not prevent a slightly above-average user from intercepting and reading all the other messages too.
And, on top of it all, the sse.php file doesn't know which user it's gathering data for, so it would have to do all users, all the time.
How do I create one sse.php file, that can handle an unlimited number of unique users, and only send the data to the appropriate user? So:
there must be a way to send some initialization data (i.e. unique user ID) to server-side file, and
there must be a way for only that one particular user to receive the information gathered
am I only sending the data to the user who opened the sse.php source
Yes.
Or will everyone logged on, who has initialized the connection, receive the same data?
No.
If each user is supposed to be receiving their own private feed,
then this method would require me to hard-code a unique event for each user
Luckily no! The SSE "event" is for sending different types of events down a single connection to a single user. A use-case might be Facebook wanting to use one event for sending chat updates, another event for sending friend requests, another for sending ads to show, etc.
In my book (Data Push Apps with HTML5 SSE, http://shop.oreilly.com/product/0636920030928.do - apologies for the plug!) I argue that it is redundant, and better included as part of the json object you are pushing.
And, on top of it all, the sse.php file doesn't know which user ...
Cookies are sent. So the typical approach is to first login the user, create a cookie that authenticates them, then call the sse script. If using a server system with sessions support (e.g. PHP), then the cookies are an implementation detail.
POST data, and custom headers, cannot be sent. So if cookies are not an option you'd have to use GET to post some authentication id (but as you note, that is not the best type of security).
An SSE is an open HTTP connection. So it will only send unique data to a user if that is how you program it. You can make this stateful by using session, cookies, IP addresses, etc. in the same was as any other HTTP request. The main limitation of SSE is that you cannot add any headers to request to connect.
I understand that command line is no web server, so you can't access $_SESSION. But I don't know what else to do.
I've been following this tutorial to create a chat using websockets: http://www.phpbuilder.com/articles/application-architecture/optimization/creating-real-time-applications-with-php-and-websockets.html
My problem is that, I do not know how to get the username of the message sender securely. I could include it in the message send function but since it's in Javascript, everyone can just edit their username to someone elses.
How could I securely get the username of the user, which is $_SESSION['username']?
var Server;
Server = new FancyWebSocket('ws://0.0.0.0:9000');
send( "test" );
I'm open to all kind of suggestions, like alternatives to websockets. I'm creating a realtime chat for my website.
First alternative is, of course, AJAX requests. AJAX doesn't have the problems of not being able to quickly and easily access the sessions that WebSockets has. Any sufficiently frequent sample rate is indistinguishable from real time.
Now, to my rather long-winded solution implemented in WebSockets:
The HTTP headers are available to the WebSocket server during the handshake, including the cookies. In the server that you're using, PHP-Websockets, the headers are stored in the $headers property.
For instance:
var_dump($user->headers);
array(14) {
["get"]=>
string(8) "/echobot"
["host"]=>
string(14) "127.0.0.1:9000"
...snip...
["cookie"]=>
string(100) "PHPSESSID=jan9uknpc06mk4ddghph4870t1; MyCookie=My+Value%21%40%23%24%25; MyNonhttponlyCookie=My+Value"
}
These cookies were generated from
session_start();
$_SESSION['Hi!'] = array('Hello!', 'where' => 'world!');
setcookie('MyCookie', 'My Value;!##$%', 0, '/', '127.0.0.1', false, true);
setcookie('MyNonhttponlyCookie', 'My Value', 0, '/', '127.0.0.1', false, false);
Thus, the value of $user->headers['cookie'] is a semicolon and space (;) delimited collection of key value pairs, where the values are URL encoded and separated from its key with an equal sign. (PHP complains if you put reserved characters in the cookie name. Thus the cookie key can not contain any url encoded values.)
A quick way to extract these are as follows
$cookies = array();
$cookiesParts = explode('; ', $user->headers['cookie']);
foreach ($cookiesParts as $cookieParts) {
$interimCookie = explode('=', $cookieParts);
$cookies[$interimCookie[0]] = urldecode($interimCookie[1]);
}
var_dump($cookies);
array(3) {
["PHPSESSID"]=>
string(26) "jan9uknpc06mk4ddghph4870t1"
["MyCookie"]=>
string(14) "My Value;!##$%"
["MyNonhttponlyCookie"]=>
string(8) "My Value"
}
We now have the session ID. Double check with session_name(), which will give you the key of the cookie that actually holds the session ID.
We could serialize and unserialize the session file as stored in the server, which is pointed at by session_save_path()... but I want to cheat.
Because the built-in session system locks the session files, we can't just keep the session file open and constantly watch for changes, nor can we lock the file ourselves for long periods of time.
It would be ideal if we could use the __get() and __set() magic methods here in the same way we'd use the $_SESSION superglobal (such as $myUser->_session['key'] = 'value';), but PHP does not allow treating these methods as arrays. Instead, we have to set a more mundanely named method.
<?php
class MyUser extends WebSocketUser {
public $session_id; // gets set somewhere. Good place is probably is your implementation of the `connected($user)` abstract method.
public getSession($key) {
session_id($this->session_id);
session_start();
$val = $_SESSION[$key];
session_write_close(); // very important!
return $val;
}
public setSession($key, $value) {
session_id($this->session_id);
session_start();
$_SESSION[$key] = value;
session_write_close(); // still very important!
}
}
(Note: I'm also pointing my feature request at this question, to base my eventual implementation of cookie parsing and session handling here, so that I can remember my research tonight as I work.)
I followed this guide to trigger a function when a comment is made. I am currently able to make an ajax call to interact with my DB when a comment is made.
FB Comments Plugin - Detect comment on page
What i want to do is save a copy of the comment in my own DB each time a comment is made. Im not sure i want to use facebook comments forever so id like to have all the data saved in my DB incase i revert to the original comment system i had.
Ive tried using jquery to get the value from the textbox and the username from the span.
var comment = $('.mentionsTextarea').val();
var username = $('.commentasName').html();
This code does not get the data. Im guessing its because its inside an iframe. Im wondering if its possible to get the data from the actual object when the comment commit is triggered. So when the event is triggered i can get the data from the comment object? Something like this.
FB.Event.subscribe('comment.create',
function(response) {
var comment = comment.text();
var username = comment.username.text();
}
I dont have the answer i wanted, but i do have a solution to this. This will get the latest comment made for a particular url.
$comments = file_get_contents('https://graph.facebook.com/comments/?ids='.$url);
$comments = json_decode($comments, true);
$comments = $comments[$url]['comments']['data'];
$latestComment = $comments[0];
$username = $latestComment['from']['name'];
$message = $latestComment['message'];
echo $username ." - ".$message;
I want to extract some data from the database without refreshing a page. What is the best possible way to do this?
I am using the following XMLHTTPRequest function to get some data (shopping cart items) from cart.php file. This file performs various functions based on the option value.
For example: option=1 means get all the shopping cart items. option=2 means delete all shopping cart items and return string "Your shopping cart is empty.". option=3, 4...and so on.
My XHR function:
function getAllCartItems()
{
if(window.XMLHttpRequest)
{
allCartItems = new XMLHttpRequest();
}
else
{
allCartItems=new ActiveXObject("Microsoft.XMLHTTP");
}
allCartItems.onreadystatechange=function()
{
if (allCartItems.readyState==4 && allCartItems.status==200)
{
document.getElementById("cartmain").innerHTML=allCartItems.responseText;
}
else if(allCartItems.readyState < 4)
{
//do nothing
}
}
var linktoexecute = "cart.php?option=1";
allCartItems.open("GET",linktoexecute,true);
allCartItems.send();
}
cart.php file looks like:
$link = mysql_connect('localhost', 'user', '123456');
if (!$link)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db('projectdatabase');
if($option == 1) //get all cart items
{
$sql = "select itemid from cart where cartid=".$_COOKIE['cart'].";";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
while($row = mysql_fetch_array($result))
{
echo $row['itemid'];
}
}
else if($option == 2)
{
//do something
}
else if($option == 3)
{
//do something
}
else if($option == 4)
{
//do something
}
My Questions:
Is there any other way I can get the data from database without
refreshing the page?
Are there any potential threats (hacking, server utilization,
performance etc) in my way of doing this thing? I believe a hacker
can flood my server be sending unnecessary requests using option=1,
2, 3 etc.
I don't think a Denial of Service attack would be your main concern, here. That concern would be just as valid is cart.php were to return HTML. No, exposing a public API for use via AJAX is pretty common practice.
One thing to keep in mind, though, is the ambiguity of both listing and deleting items via the same URL. It would be a good idea to (at the very least) separate those actions (or "methods") into distinct URLs (for example: /cart/list and /cart/clear).
If you're willing to go a step further, you should consider implementing a "RESTful" API. This would mean, among other things, that methods can only be called using the correct HTTP verb. You've possibly only heard of GET and POST, but there's also PUT and DELETE, amongst others. The reason behind this is to make the methods idempotent, meaning that they do the same thing again and again, no matter how many times you call them. For example, a GET call to /cart will always list the contents and a DELETE call to /cart will always delete all items in the cart.
Although it is probably not practical to write a full REST API for your shopping cart, I'm sure some of the principles may help you build a more robust system.
Some reading material: A Brief Introduction to REST.
Ajax is the best option for the purpose.
Now sending and receiving data with Ajax is done best using XML. So use of Web services is the recommended option from me. You can use a SOAP / REST web service to bring data from a database on request.
You can use this Link to understand more on Webservices.
For the tutorials enough articles are available in the Internet.
you're using a XMLHttpRequest object, so you don't refresh your page (it's AJAX), or there's something you haven't tell
if a hacker want to DDOS your website, or your database, he can use any of its page... As long as you don't transfer string between client and server that will be used in your SQL requests, that should be OK
I'd warn you about the use of raw text response display. I encourage you to format your response as XML or JSON to correctly locate objects that needs to be inserted into the DOM, and to return an tag to correctly handle errors (the die("i'm your father luke") won't help any of your user) and to display them in a special area of your web page
First, you should consider separating different parts of your application. Having a general file that performs every other tasks related to carts, violates all sorts of software design principles.
Second, the first vulnerability is SQL injection. You should NEVER just concatenate the input to your SQL.
Suppose I posted 1; TRUNCATE TABLE cart;. Then your SQL would look like:
select itemid from cart where cartid=1; TRUNCATE TABLE cart; which first selects the item in question, then ruins your database.
You should write something like this:
$item = $_COOKIE['cart'];
$item = preg_replace_all("['\"]", "\\$1", $item);
To avoid refreshing, you can put a link on your page. Something like, Refresh
In terms of security, it will always pay to introduce a database layer concerned with just your data, regardless of your business logic, then adding a service layer dependent on the database layer, which would provide facilities to perform business layer actions.
You should also take #PPvG recommendation into note, and -- using Apache's mod_rewrite or other similar facilities -- make your URLs more meaningful.
Another note: try to encapsulate your data in JSON or XML format. I'd recommend the use of json_encode(); on the server side, and JSON.parse(); on the client side. This would ensure a secure delivery.