I'm working on a AngularJS / Phonegap / PHP (Zend) project.
I want the users to login via JWT. (this seems the best options since cookies not work). I've found a tutorial to manage it on the angular side
I went googling a lot and found out that google uses the https://github.com/luciferous/jwt version. Also I found a newer one based on that from firebase ( https://github.com/firebase/php-jwt )
(1) Which one should I use?
I'm using the luciferous now and when I create a token via:
$ENV_var = "whatever":
$token = encode("id: 5", $ENV_var);
It returns: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.ImlkOiA1Ig.KtG-rOleZwiDhbMnaLI1vIOczPYUM2Az1KfIeygJ7E0 which is unvalid here but valid if I decode it with the same script.
(2) Why is this? is this because jwt.io is made with/by Auth0?
(3)Also I don't get when/why I should use the "sign method" instead of encode (below: from github luciferous)
public static function sign($msg, $key, $method = 'HS256')
{
$methods = array(
'HS256' => 'sha256',
'HS384' => 'sha384',
'HS512' => 'sha512',
);
if (empty($methods[$method])) {
throw new DomainException('Algorithm not supported');
}
return hash_hmac($methods[$method], $msg, $key, true);
}
1) I would recommend using the firebase implementation, since it is maintained more and has composer support.
The payload that is passed into the encode method should be an array of "claims" see here e.g.
$payload = array('sub' => 1, 'iss' => 'example.com');
$secret = 'someSecretKey';
$token = JWT::encode($payload, $secret);
2) because the token you are generating is not based on an array or contain any required claims.
3) you should generally use the encode/decode methods as they will call sign internally
Ad 1. Both are fine to use, however the second has got better documentation. I personally prefer to work with https://github.com/firebase/php-jwt.
You said that JWT generated is not valid. I have tested it and it worked (it got decoded correctly), just make sure to use correct algorithm "HS256" and your secret.
Ad 2. This question is not clear, can you please clarify?
Ad 3. Encode method of that class calls sign. You don't have to call sign yourself, just encode.
Related
When im check JSON encode with print_r it look fine => {"expiry":1636191448,"auth":true}
Then im try to store it inside cookie,
but it turn into like this when i see it in browser cookies value => %7B%22expiry%22%3A1636191866%2C%22auth%22%3Atrue%7D
Can anyone tell me how to fix it. Im not use this for permission system, but for other thing like read it in javascript but i got error when try to parse it
Uncaught SyntaxError: Unexpected token % in JSON at position 0
at JSON.parse ()
.
This are the line of code in my php file
if (Cookie::exists(Config::get('client/cookie_name'))) {
$client = json_decode(Cookie::get(Config::get('client/cookie_name')), true);
$expiry = $client['expiry'];
} else {
$client = array (
'expiry' => time() + Config::get('client/cookie_expiry')
);
}
$client['auth'] = true;
$client = json_encode($client);
Cookie::update(Config::get('client/cookie_name'), $client, $expiry);
Cookies are often URL-encoded (but sometimes different encodings are used). Since this isn't really standardized and by spec there is only a handful of characters that must be encoded somehow (not specified how), different systems may take different routes in handling cookie encoding, and therefore reading cookies set by one system using another system can cause issues like these.
In your case, you can call decodeURIComponent on the value first:
const json = decodeURIComponent(encodedCookieValue)
const data = JSON.parse(json)
Further reading: Should cookie values be URL encoded?
I am creating a project and I want to have a demo for users to test but they will have access to the admin area. I want to prevent any form with post method from working. I did that with Javascript by preventing the default methods.
I was wondering if there a better way to do so, in case the Javascript never loaded.
I was going to work with the view and the controller but its hassle when the project is big, doing it with a middleware is the best thing to go with in my opinion but I still couldn't reach out its logic. What would you guys recommend the logic should look like?
Consider the #Flash answer, it's a good idea. Another way could be changing the method in controller. For example if you have a store method in ExampleController that saves/process the form, comment the lines inside the method like this:
public function store(Request $request)
{
/*
$request->validate([
'name' => 'required',
'display' => 'required',
]);
$category = new Category();
$category->parent_id = $request->parent_id;
$category->name = $request->name;
$category->display = $request->display;
$category->save();
return redirect()->route('category.add');
*/
}
Create a dummy user in your database and have a middleware in place(if you did not have it before).
Save the demo user ID in a config file, let's say config/app.php.
When someone visits your demo site, ask them to login and provide them the demo user credentials.
Create a session after the login(which you would anyway) with that user and whenever a post or any request that would affect the database is made, check like below-
Middleware Code:
if(Auth::user()->id === config('app.dummy_user_id'){
if($request->getMethod() === 'GET' || $request->getMethod() === 'OPTIONS'){
// for OPTIONS, you would play with the headers which I leave to you to edit
return $next($request);
}else{
return redirect()->back();
}
}
// your further processing
return $next($request);
Before I get to the question, let me explain how we have things set up.
We have a proxy.php file, in which class Proxy is defined with functions that call upon a rest for creating/editing/getting Wordpress posts, fields etc.
Then, we have a proxyhandler.php, in which Proxy class is initialized and serves as a handle between proxy.php and a javascript file.
In javascript file we have an ajax call to proxyhandler.php in which we send our secret and other data.
Now, the problem arises here:
We define the secret through wp_localize_script, by using md5 custom string + timestamp. We send the encripted string and timestamp through ajax to proxy handler, where we use the previous (hardcoded inside proxyhandler) string and timestamp to generate a md5 string again, and check the one sent against the one generated. If they are the same, we continue by doing whatever was requested, if they dont fit, we just return that the secret didn't match.
Now, the real issue comes here - by using wp_localize_script, the variable for the secret is global and as such, anyone can utilize it via dev tools and can send any ajax request to proxyhandler that they want.
What would be the proper procedure to make it more secure? We've thought of doing this:
Instead of using wp_localize_script, we put the script inside a php file, we define the secret using a php variable and then simply echo the secret file into ajax. Would this be viable, or are there any other ways?
Instead of sending an encrypted string in global scope, then check against it, you should use nonce in your AJAX request:
var data = {
action: 'your_action',
whatever_data: who_know,
_ajax_nonce: <?= wp_create_nonce('your_ajax_nonce') ?>
};
Then, use check_ajax_refer() to verify that nonce:
function your_callback_function()
{
// Make sure to verify nonce
check_ajax_refer('your_ajax_nonce');
// If logged in user, make sure to check capabilities.
if ( current_user_can($capability) ) {
// Process data.
} else {
// Do something else.
}
...
}
Depend on the AJAX METHOD, you can use $_METHOD['whatever_data'] to retrieve who_know data without needing to use wp_localize_script().
Also remember that we can allow only logged in users process AJAX data:
// For logged in users
add_action('wp_ajax_your_action', 'your_callback_function');
// Remove for none logged in users
// add_action('wp_ajax_nopriv_your_action', 'your_callback_function');
The final thing is to make sure NONCE_KEY and NONCE_SALT in your wp-config.php are secure.
I'm not so much of a framework fan but I have been made to use it because I am working on a project that others may edit later.
I am using the CodeIgniter framework (I'm kinda new on it).
I am using jquery $.post(url, function() {}) to asynchronously call a login parser that is in the root directory under a folder called php-parser I realized this folder does not make use of any of the CodeIgniter's ready made class. I decided to move the folder php-parser into application/libraries but when I tried to use jQuery to call it referencing the full path /application/libraries/php-parser/the-script.php, it return a 403 forbidden error
What do you think I can do? Some people said I could make the script a controller but here is what is going on, It's a popup modal login page. From any page if you click the login / register button, the modal pops up, how can I make a controller and a model for that (if I'm to follow that procedure).
Added: I put the modal content at the end of the footer which is included on all pages, how do I get to create a controller for that kind of modal? Any help!
When dealing with MVC (at least the way you are using it) you have three parts:
The Model - in this case this is the code which interacts with your database.
The View - the code which formats the data you are sending back to the browser
The Controller - the code which connects the two together and might have some business logic in it.
You also have some routing code which maps a URL onto the right controller for that URL.
Browsers (and other clients) only interact with web servers through URLs.
So you absolutely need to have a Controller set up to handle the request from the browser.
If you are doing this the quick and dirty way, then your controller will just get the username and password from the POST request, check it against the database with the model, and then squirt either "Success!" or "Fail!" into the view (which is probably best written as something that returns JSON formatted back to the browser).
If you are being sensibly robust about this then the view will have logic something along the lines of:
Does the browser explicitly include JSON in the accept header?
If so, send back a bit of JSON saying "success" or "failure" (or true / false, or whatever makes sense for you).
Does it not? Then either return a "Sorry, you failed to login!" HTML document or a redirect back to the page they came from (so it will reload in the logged in state).
That way, if the JavaScript fails for any reason, the plain HTML form which was progressively enhanced with the Ajax JavaScript will still function. (NB: You have to write it that way!).
jQuery will automatically include a JSON friendly Accept header if you say dataType: "json" in the Ajax options.
Yes, you will need to put your file inside the libraries folder(if the class is separate from codeigniter or is shared among many controllers, if not a Model would suffice), then create a controller for it.
class Ajax_Controller extends CI_Controller
{
public $statusCode = 200;
public $response = array();
public function __construct()
{
parent::__construct();
if(!$this->is_ajax_request()){
return; // direct access not allowed
}
$this->response = array(
'error' => false,
'text' => "",
'fields' => array()
);
}
public function sendResponse()
{
return $this->output
->set_status_header($this->statusCode)
->set_content_type('application/json')
->set_output(json_encode($this->response));
}
}
class Auth extends Ajax_Controller
{
public function __construct()
{
parent::__construct();
$this->load->library('php-parser/script', 'authentication');
}
public function login()
{
if(!$this->form_validation->run()){
$this->response = array(
'error' => true,
'text' => "The form has some errors",
'fields' => array(
'username' => form_error('username'),
'password' => form_error('password')
)
);
return $this->sendResponse();
}
$username= $this->input->post('username');
$password= $this->input->post('password');
if(!$this->authentication->login($username, $password)){
$this->response = array(
'error' => true,
'text' => "incorrect username/password combination",
'fields' => array()
);
$this->statusCode = 401;
return $this->sendResponse();
}
}
}
I've been searching throughout the day to find a way to figure this out, but without sucess and I thought that maybe someone here could help ?
I am trying to use a secrete password in my .Js file but I can't write it directly in the file because everyone could see it when accessing the source code. e.g I need to send this password using ajax to another page to make sure that the HttpRequest is from my website not from another forge httprequest . Is that possible because I've tried everything else like Authentication Forms but that didn't help.
I'm using asp.net and HttpHandler as the page that returns data .
What you can do is generate a key that is valid up to a set time using PHP like so:
$password = "some random string";
$key = md5($password . $_SERVER['REQUEST_TIME']) . "|" . $_SERVER['REQUEST_TIME'];
This way you know when the key was generated, and if it's been tampered with because:
function check($key) {
list($hash, $timestamp) = explode("|", $key, 2);
if ($hash !== md5($password . $key)) {
throw new Exception("Naughty!");
}
if ($timestamp < $_SERVER['REQUEST_TIME'] < 60*60) {
throw new Exception("too old");
}
}
The down side is that people who don't refresh the page very often (in my example this is 1 hour) their key will expire.
Another issue is that your 'attacker' could technically first scrape a page to get a new key and use that, and scrape again when it expires and so on.
This solution works very good for protecting against hotlinking.
This is how it's done in MVC. Unfortunately, it doesn't look like the same security goodness has made it to WebForms (at least as far as I can tell).