How can I make an HTML (and CSS/PHP/JavaScript) document which only allows certain IP addresses on a page?
(I am not asking how to find IP address with PHP, but how to allow access to a page based on an IP address.)
put this on the top of your php file and update the allowedIps variable with the IPs that you want to allow.
$allowedIps = ['198.x.x.x', '200.x.x.x'];
$userIp = $_SERVER['REMOTE_ADDR'];
if (!in_array($userIp, $allowedIps)) {
exit('Unauthorized');
}
for non PHP files (eg .html, .css) you will have to update your .htaccess file to add file specific permission. The following SOF thread should help: (assuming you are using apache server)
.htaccess: how to restrict access to a single file by IP?
If you dont want to bother with the code, put your site on Cloudflare and block ips
Try this with PHP :
function CheckIPAccess() {
//allowed IP. Change it to the IP addresses you want to allow to access your webpage
$allowedip = '127.0.0.1';
$ip = $_SERVER['REMOTE_ADDR'];
return ($ip == $allowedip);
}
Usually, IP restrictions are done at the web-server configuration level, so that unauthorized IPs simply can't reach your code at all.
It would actually be quite messy to try to do this kind of check within your application – "you'd undoubtedly miss one" – but the server can easily do it for you.
(I do not recommend attempting to use IPs for privilege checking and so forth ... "IPs change. Frequently. Very messy. Very ...")
Even stronger yet would be firewalls, and maybe VPNs. You really want to keep intruders as far away as possible and to give them as little information as possible. (For instance, why should they even be able to detect that the web-server exists?) Strive to make the entire setup as "hardened" as possible.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I'm making a website and there is a page on said website which I would like only certain people to access, with a password. I was wondering the best way to go about it simply and securely, and would love some example code if any exists.
To clarify, I would like to add a feature to a page on my website which prevents anyone visiting the site from going to that page unless they enter a password. I'm mostly looking for HTML, JS, or JQuery solutions, as this is only going to be for the users of the website.
The simplest way that I've come across is using an htpasswd file (which looks very similar to /etc/passwd if you are familiar with that), then setting up your webserver to point at it.
# create htpasswd file
htpasswd -c /path/htpasswd
# add user to htpasswd file (you'll be prompted for password)
htpasswd /path/htpasswd loginuser
Within your nginx.conf , set it up like this
server {
listen 80 yourserver;
listen [::]80 yourserver ipv6only=on;
root /var/www/yourserver;
index index.html;
location /public {
# ...
}
# everything under /private requires a login
location /private {
auth_basic "Restricted Content";
auth_basic_user_file /path/htpasswd;
}
}
There's a really good tutorial on this setup, that I shamelessly robbed for this answer here:
https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-nginx-on-ubuntu-14-04
Then for anything over/above that, nginx's documentation is excellent as well (if that is the webserver you are using).
https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html
One trap with this setup is that nginx only allows password hashes that are supported by your operating system's crypt module. So linux for example wouldn't necessarily have bcrypt, but most of the BSDs would. You can find what your OS's crypt module supports using man crypt .
|
If you're looking for something where you have a little more control, you can have a URL that you GET a website with form data, which POSTs the login information to a URL you can handle the login details yourself. This is python/flask - I'm not sure it is what you are looking for bsaed on your tags but it may still be helpful.
https://pythonspot.com/login-authentication-with-flask/
I hope this was helpful :) good luck!
Depending on what frameworks, applications etc. you are using to create your website, and If you want create an account system or just a protected area, there are many different ways.
1. .htaccess:
Assuming you are using a NCSA-compatible webserver such as apache and want to restrict access to a certain path, the simplest (yet by far not safest) way to do that would be to use a simple .htaccess-file.
simply put a file with that exact name into the folder you want to protect with following content:
AuthType Basic
AuthName "Enter Credentials Here"
AuthUserFile /full/path/to/.htpasswd
Require valid-user
and create a .htpasswd file in a safe place containing
username:password
or, if you care about people hacking your server getting the password:
username:hash
you can generate hashes using online-.htpasswd-generators.
Make sure to enter the path to your .htpasswd correctly into your .htaccess!
The .htaccess file will make the server ask for basic username/password authentication, show the message "Enter Credentials Here" to the user and require the users browser to send any valid credentials to your server. Valid credentials mean any username/password-pair in your .htpasswd file. Just know that the user's browser will always send the credentials to your server unencrypted, so make sure to enable https, if you care about the password not being stolen from your users. And tell them not to write it down etc. basic password safety.
2. Fancy Account System using SQL
This is more complicated an probably not what you want, so I will just give basic advice: Read about sql injection and make sure you fully understand it and how to avoid it. Read about password hashing and salting. Read about safe passwords (phrases) to advice your users. Read about html forms and how to parse them using your framework. Read about encryption. Then create a concept that fits your needs and implement it.
If you are using PHP then this is simple solution:
<?php
if(!isset($_POST["password"])){
header("location:pwdnotcorrect.php");
return;
}
$pwd=$_POST["password"];
if($pwd!="yourpassword"){
header("location:pwdnotcorrect.php");
return;
}?>
<!--Your HTML Code starts here--->
Send POST request with password to this page using form
If password not correct then this page redirect you to new page.
I'm making a chrome extension that injects an iframe on a webpage and show some stuff.
Content loaded in iframe is from https://example.com and i have full control over it. I'm trying to access cookies of https://example.com from the iframe (which i think should be available) by document.cookie. This is not letting me access httponly flagged cookie and i do not know reason for this. After all this is no cross-domain. Is it?
Here is the code i'm using to get cookie
jQuery("#performAction").click(function(e) {
e.preventDefault();
console.log(document.domain); // https://example.com
var cookies = document.cookie;
console.log('cookies', cookies);
var httpFlaggedCookie1 = getCookie("login_sess");
var httpFlaggedCookie2 = getCookie("login_pass");
console.log('httpFlaggedCookie1 ', httpFlaggedCookie1 ); // shows blank
console.log('httpFlaggedCookie2 ', httpFlaggedCookie2 ); // shows blank
if(httpFlaggedCookie2 != "" && httpFlaggedCookie2 != ""){
doSomething();
} else{
somethingElse();
}
});
Any suggestions what can be done for this?
By default in Chrome, HttpOnly cookies are prevented to be read and written in JavaScript.
However, since you're writing a chrome extensions, you could use chrome.cookies.get and chrome.cookies.set to read/write, with cookies permissions declared in manifest.json. And be aware chrome.cookies can be only accessed in background page, so maybe you would need to do something with Message Passing
Alright folks. I struggled mightily to make httponly cookies show up in iframes after third party cookies have been deprecated. Eventually I was able to solve the issue:
Here is what I came up with:
Install a service worker whose script is rendered by your application server (eg in PHP). In there, you can output the cookies, in a closure, so no other scripts or even injected functions can read them. Attempts to load this same URL from other user-agents will NOT get the cookies, so it’s secure.
Yes the service workers are unloaded periodically, but every time it’s loaded again, it’ll have the latest cookies due to #1.
In your server-side code response rendering, for every time you add a Set-Cookie header, also add a Set-Cookie-JS header with the same content. Make the Service Worker intercept this response, read that cookie, and update the private object in the closure.
In the “fetch” event, add a special request header such as Cookie-JS, and pass what would have been passed in the cookie. Add this to the request headers before sending the request to the server. In this way, you can send all “httponly” cookies back to the server, without the Javascript being able to see them, even if actual cookies are blocked!
On your server, process the Cookie-JS header and merge that into your usual Cookies mechanism, then proceed to run the rest of your code as usual.
Although this seems secure to me — I’d appreciate if anyone reported a security flaw!! — there is a better mechanism than cookies.
Consider using non-extractable private keys such as ECDSA to sign hashes of payloads, also using a service worker. (In super-large payloads like videos, you may want your hash to sample only a part of the payload.) Let the client generate the key pair when a new session is established, and send the public key along with every request. On the server, store the public key in a session. You should also have a database table with the (publicKey, cookieName) as the primary key. You can then look up all the cookies for the user based on their public key — which is secure because the key is non-extractable.
This scheme is actually more secure than cookies, because cookies are bearer tokens and are sometimes subject to session fixation attacks, or man-in-the-middle attacks (even with https). Request payloads can be forged on the server and the end-user cannot prove they didn’t make that request. But with this second approach, the user’s service worker is signing everything on the client side.
A final note of caution: the way the Web works, you still have to trust the server that hosts the domain of the site you’re on. It could just as easily ship JS code to you one day to sign anything with the private key you generated. But it cannot steal the private key itself, so it can only sign things when you’ve loaded the page. So, technically, if your browser is set to cache a top-level page for “100 years”, and that page contains subresource integrity on each resource it loads, then you can be sure the code won’t change on you. I wish browsers would show some sort of green padlock under these conditions. Even better would be if auditors of websites could specify a hash of such a top-level page, and the browser’s green padlock would link to security reviews published under that hash (on, say, IPFS, or at a Web URL that also has a hash). In short — this way websites could finally ship code you could trust would be immutable for each URL (eg version of an app) and others could publish security audits and other evaluations of such code.
Maybe I should make a browser extension to do just that!
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.
I am starting to build/design a new single page web application and really wanted to primarily use client-side technology (HTML, CSS, JavaScript/CoffeScript) for the front-end while having a thin REST API back-end to serve data to the front-end. An issue that has come up is about the security of JavaScript. For example, there are going to be certain links and UI elements that will only be displayed depending on the roles and resources the user has attached to them. When the user logs in, it will make a REST call that will validate the credentials and then return back a json object that has all the permissions for that user which will be stored in a JavaScript object.
Lets take this piece of javascript:
// Generated by CoffeeScript 1.3.3
(function() {
var acl, permissions, root;
root = typeof exports !== "undefined" && exports !== null ? exports : this;
permissions = {
//data…
};
acl = {
hasPermission: function(resource, permission, instanceId) {
//code….
}
};
root.acl = acl;
}).call(this);
Now this code setup make sure even through the console, no one can modify the variable permissions. The issue here is that since this is a single page application, I might want to update the permissions without having to refresh the page (maybe they add a record that then needs to be added to thier permissions). The only way I can think of doing this is by adding something like
setPermission: function(resource, permission, instanceId){
//code…
}
to the acl object however if I do that, that mean someone in the browser console could also use that to add permissions to themself that they should not have. Is there any way to add code that can not be accessed from the browser console however can be accessed from code in the JavaScript files?
Now even if I could prevent the issue described above, I still have a bigger one. No matter what I am going to need to have the hasPermission functionality however when it is declared this way, I can in the browser console overwrite that method by just doing:
acl.hasPermission(resource, permission, instanceId){return true;}
and now I would be able to see everything. Is there anyway to define this method is such a way that a user can not override it (like marking it as final or something)?
Something to note is that every REST API call is also going to check the permissions too so even if they were to see something they should not, they would still not be able to do anything and the REST API would regret the request because of permissions issue. One suggestion has been made to generate the template on the server side however I really don't like that idea as it is creating a very strong coupling between the front-end and back-end technology stacks. If for example for whatever reason we need to move form PHP to Python or Ruby, if the templates are built on the client-side in JavaScript, I only have to re-build the REST API and all the front-end code can stay the same but that is not the case if I am generating templates on the server side.
Whatever you do: you have to check all the permissions on the server-side as well (in your REST backend, as you noted). No matter what hoops you jump through, someone will be able to make a REST call that they are not supposed to make.
This effectively makes your client-side security system an optimization: you try to display only allowed operations to the user and you try to avoid round-trips to the server to fetch what is allowed.
As such you don't really need to care if a user can "hack" it: if they break your application, they can keep both parts. Nothing wrong can happen, because the server won't let them execute an action that they are not authorized to.
However, I'd still write the client-side code in a way that it expect an "access denied" as a valid answer (and not necessary an exception). There are many reasons why that response might come: If the permissions of the logged-in user are changed while he has a browser open, then the security descriptions of the client no longer match the server and that situation should be handled gracefully (display "Sorry, this operation is not permitted" and reload the security descriptions, for example).
Don't ever trust Javascript code or the front-end in general. People can even modify the code before it reaches your browser (sniffers etc) and most variables are accessible and modifiable anyways... Trust me: you are never going to be safe on the front-end :)
Always check credentials on the server-side, never only on the front-end!
In modern browsers, you can use Object.freeze or Object.defineProperty to make sure the hasPermission method cannot be redefined.
I don't know yet how to overcome the problem with setPermission. Maybe it's best to just rely on the server-side security there, which as you said you have anyway.
Lets say I have a php generated javasrcipt file that has the user's name, id number and email adress that is currently logged in. Would a simply document.location.href look up prevent remotes sites from determining the currently logged in user?
Would this be safe?
if(window.document.location.hostname == 'domain.com')
var user = {
name:'me',
id:234243,
email:'email#email.com'
};
else alert('Sorry you may not request this info cross sites.');
Initially it appears safe to me.
EDIT: I had initially thought this was obvious but I am using cookies to determine the currently logged in user. I am just trying to prevent cross domain access to the users info. For example if the if statement was removed malicious site A could embed the javascript file and access the users info. By adding the if statement the user js object should never appear. Cross site ajax isn't supported therefore only through javascript insertion could the malicious site attempt to determine the currently logged in user.
EDIT 2: Would checking my http_refer using php be safe? What if caching is also enabled for the client? For example if the user visits my site A where the user script is downloaded and then later visits site B malicious site would the script be cached, therefore bypassing the need for the server to check the user's http_refer?
You're basically saying "here's the keys to the bank vault, here's the guard's schedule, and here's the staff schedule. But hey, if you're not from the Acme Security Company, pretend I didn't give this to you".
"oh, sure, no problem, lemme just pretend to shred this note and go rent a large truck haul away your vault contents with"
You really just don't want to try something like this. Suppose I'm running an evil site; what do I do?
<script>
RegExp.prototype.test = function() { return true; };
</script>
<script src="http://yoursite.example.com/dynamicjs.php"></script>
<script>
alert("Look at the data I stole: " + user);
</script>
No, what you have there is not "safe" in that it will reveal those details to anyone requesting the HTML page containing that JavaScript. All they have to do is look at the text (including script) returned by the server.
What it comes down to is this: Either you have authenticated the other end to your satisfaction, in which case you don't need the check in the JavaScript, or you haven't, in which case you don't want to output the details to the response at all. There's no purpose whatsoever to that client-side if statement. Try this: http://jsbin.com/aboze5 It'll say you can't request the data; then do a View Source, and note that you can see the data.
Instead, you need to check the origin of the request server-side and not output those details in the script at all if the origin of the request is not authenticated.
Update 1: Below you said:
I was specifically trying to determine if document.location.href could be falsified.
Yes, document.location can be falsified through shadowing the document symbol (although you might be able to detect that if you tried hard enough):
(function() {
var document; // Shadow the symbol
document = {
location: {
href: "http://example.com/foo.html"
}
};
alert("document.location.href = " + document.location.href);
})();
Live copy
Cross-domain checks must happen within the browser's internals, nothing at the level of your JavaScript code can do it securely and robustly.
But that really doesn't matter. Even if it couldn't be falsified, the quoted example code doesn't protect the data. By the time the client-side check is done, the data has already been sent to the client.
Update 2: You've added a note about checking the HTTP_REFERER (sic) header (yes, it really is misspelled). Sadly, no, you can't trust that. HTTP_REFERER can be spoofed, and separately it can be suppressed.
Off-topic: You're probably already doing this, but: When transferring personal details you've promised to keep confidential (I don't know whether you have, but hopefully so), use HTTPS (e.g., SSL). But it's important to remember that while HTTPS ensures that data cannot be read in transit, it does nothing to ensure that the origin of the request is authenticated. E.g., you know the conversation is secure (within reason and current practice), but you don't necessarily know who you're talking to. There's where authentication comes into it.