Error:
Unable to verify your data submission error
Create one public function in Yii2. But, submit data not accept in this method,
see following error images. Why is this happen?
If you create the form manually (i.e. without using the yii form methods), you should add an input field like this:
<input type="hidden" name="_csrf" value="<?=Yii::$app->request->getCsrfToken()?>" />
source: http://zero-exception.blogspot.com/2015/01/yii2-using-csrf-token.html
Add this in the head section of your layout: <?= Html::csrfMetaTags() ?>
There are various solutions to this problem, I guess understanding why it happened in the first place helps solve the problem.
It is either caused by an invalid csrf token,user generated csrf token, expired csrf token, all these 'csrf' issues will arise when you have custom forms built not using the 'ActiveForm' class.
If CSRF is not the issue,
Its other cause occurs when you try to upload multiple files and the web server cannot handle the load. Some properties to check on this to make sure you are on the right track is to claculate the size of files one is attempting to upload and check the web server's post_max_size and upload_max_filesize
If you are running linux, check php.ini file for inputs like these:
; Maximum size of POST data that PHP will accept.
; Its value may be 0 to disable the limit. It is ignored if POST data reading
; is disabled through enable_post_data_reading.
; http://php.net/post-max-size
post_max_size = 8M
; Whether to allow HTTP file uploads.
; http://php.net/file-uploads
file_uploads = On
; Maximum allowed size for uploaded files.
; http://php.net/upload-max-filesize
upload_max_filesize = 2M
Based on your calculations, adjust the above php.ini parameters to suite your needs, then test.
I had a similar problem and I solved it.
To permanently disable csrf validation in whole application add below code in your configurations.
$config = [
'components' => [
'request' => [
'enableCsrfValidation' => false,
],
],
];
Also sometimes you can get this error using Yii 2.0 due to the post_max_size, upload_max_filesize, max_input_time also too maybe the webserver can be trimming the post so verify on nginx - client_max_body_size or in apache - LimitRequestBody
Disable for only specific action
/**
* #inheritdoc
*/
public function beforeAction($action)
{
if ($action->id == 'my-action') {
$this->enableCsrfValidation = false;
}
return parent::beforeAction($action);
}
Check whether there is hidden input in your form with CSRF token. It should look like
<input type="hidden" name="_csrf" value="ZEZ6Y0xrY3ARGS42fTwhMQgkDgF6BCEGEx4SMXQMBR4CPy0iPCIwNQ==">
A long story has been discussed here github
So disabling csrf somehow unsure for ajax request. I have met this issue many times.
So remember to send _csrf key when you send data by POST via ajax.
Updated from yii 2.0.12 to 2.0.30
Have this bad request error 400
Got the Html::csrfMetaTags() in the header layout.
using activeform,therefore is not caused by missing csrf token in the
form. And checked already through inspect.
I solved this through adding below code to the backend/config/main.php.
'components' => [
'request' => [
'csrfParam' => '_backend_csrf',
],
Is it a correct way or will it cause security issue?
A little differentiation to dchakarov's answer due to Yii2 tiers using instead of
_csrf variable _frontendCsrf.
<input type="hidden" name="_frontendCsrf" value="<?=Yii::$app->request->getCsrfToken()?>" />
This is a second time this question did not help me even though I posted a comment previously, so I have to post a response.
$csrf = \yii::$app->request->csrfParam;
$token = \yii::$app->request->csrfToken;
//start from
echo Html::hiddenInput($csrf,$token);
//end from
Switched website form https to http and had the issue come up. Updated the request config by commenting the below lines to resolve.
'request' => [
'cookieValidationKey' => 'SomeRandomKeyValidationString',
//'csrfCookie' => [
// 'httpOnly' => true,
// 'secure' => true,
//],
Add this in your controller:
public $enableCsrfValidation = false;
Related
This is very strange, I'm building an SPA with Laravel and Vue js. I'm using Laravel Passport and JWT for Authentication. All of a sudden my Validation errors aren't displaying when I submit any of my forms. I keep getting this error:
Failed to load resource: the server responded with a status of 400 ()
If you fill in the Forms and click submit everything still works in the application, I see the success message and the data gets saved in the database. I have no idea what is causing this, at first I thought it had to do with the Recaptcha code that I implemented but now, I'm not 100% sure that that's the problem, since I removed all of the related code and tried to submit my forms again and still got a 400 error.
I know these details are pretty vague, but if anyone has idea what this could be related to it would be greatly appreciated.
Thank you.
You need to return a JSON error handle if you are using an API call.
The Laravel default error handling for validation is to throw Exception thru the blade that you can access as $errors
If you want to make your own validation use the validator facade.
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
public function store(Request $request) {
$validation = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required',
'password' => 'required',
]);
if($validation->fails()) {
return response()->json([
'status' => 'failed',
'message' => $validation->errors(),
], 400);
}
}
Thank you to those who commented or answered. I did actually figure it out. I added a couple of functions into my Exceptions/Handler.php file. I built this SPA based off of a Free Youtube Course and I grabbed the code that I placed in the Handler.php file after following a different paid course on Udemy. I didn't think these functions would cause any harm but they did. After removing them, everything is working great and back to normal. Thank you.
I initially created an app and starting developing it using only the data:read scope. I have now realized that I need the data:create scope as well.
Is there something within the app settings that I need to change?
Does the create scope include read permissions and then write scope include create and read - or does that scope have to be sent separately?
If separately, how is that done when the user is granting permission to the app? Is it something like &scope=data:read&scope:create
I don't have to store and then use two tokens, do I?
How is this handled when using curl? Are the read and create scopes sent in an array like so ...
$response = $client->request('POST', 'https://developer.api.autodesk.com/authentication/v1/gettoken', [
'form_params' => [
'grant_type' => 'authorization_code',
'code' => $authCode,
'client_id' => $FusionID,
'client_secret' => $FusionSecret,
'redirect_uri' => 'https://www.example.com/fusionauth',
'scope' => array('data'=>'create', 'data'=>'read')
]
]);
Again, it may be that you only use the scope you need and you have to store separate tokens, but that doesn't seem right to me.
Is there something within the app settings that I need to change?
If by app settings you meant in the Forge App portal then you only have to specify there the APIs (make sure they are checked on the page) that your app will need to access.
Does the create scope include read permissions and then write scope include create and read - or does that scope have to be sent separately?
No doesn't work like that - you will need to specify each one of them explicitly.
If separately, how is that done when the user is granting permission to the app? Is it something like &scope=data:read&scope:create
Nope the scope variables are delimited by space. For 3-legged oauth you will need to obtain an authorization code through redirecting the user to authenticate at our login portal before you go for access tokens and there you will need to indicate the redirection address and scope combinations in the request URL (don't forget to URLEncode them) such as https://developer.api.autodesk.com/authentication/v1/authorize?response_type=code&client_id=obQDn8P0GanGFQha4ngKKVWcxwyvFAGE&redirect_uri=http%3A%2F%2Fsampleapp.com%2Foauth%2Fcallback%3Ffoo%3Dbar&scope=data:read. See here for details.
And check out our official PHP client SDK - should save you tons of effort and time.
I don't have to store and then use two tokens, do I?
If your token carries sufficient permissions (say data:read and data:create) then no.
How is this handled when using curl? Are the read and create scopes sent in an array like so ...
For cURL see samples here: https://forge.autodesk.com/en/docs/oauth/v2/tutorials/get-2-legged-token/
And like we went through above you will need to specify the scopes when redirecting the user to authenticate so in your request to fetch the eventual access token you'd should something like:
$response = $client->request('POST', 'https://developer.api.autodesk.com/authentication/v1/gettoken', [
'form_params' => [
'grant_type' => 'authorization_code',
'code' => $authCode,
'client_id' => $FusionID,
'client_secret' => $FusionSecret,
'redirect_uri' => 'https://www.example.com/fusionauth'
)
]
]);
I'm a serious newbie as it comes to Zend and I'm now forced to work with Zend 3 (and learn it). Fellow developers have done parts of the application and now I'm cloning it on my side.
I receive "Database not selected" in the error log - I have set database.local.php and I think they've set everything else. Credentials are correct.
I'm working on Windows.
Is there anything else I could be missing as it comes to settings or database connection?
Thanks. I will provide any additional info if needed.
As we're dealing with both Zend Framework AND a configuration issue, for your next question, please make sure to also include file paths and such.
I'm proceeding with this answer under the assumption that you've created your file here: /config/database.local.php.
Note: using ZF3 myself, I, of course, tried to find your error message "Database not selected", however it comes back with no results. Make sure you copy and paste error messages so users of any framework, cms or another system can more easily help you out.
You'll find the problem you're facing in the application.config.php file (in the /config folder. In here you'll find the following config:
// Retrieve list of modules used in this application.
'modules' => require __DIR__ . '/modules.config.php',
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => [
// ... other config
// An array of paths from which to glob configuration files after
// modules are loaded. These effectively override configuration
// provided by modules themselves. Paths may use GLOB_BRACE notation.
'config_glob_paths' => [
realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local,{,*.}deploy,{,*.}development}.php',
],
// ... other config
],
Any of the *.local.php or *.global.php config files should be placed in /config/autoload/. Though, if you modify the above config, you could technically place it wherever you'd like.
Next, make sure you have the Zend\Db module enabled in your configuration. Open up the /config/modules.config.php file and make sure Zend\Db is in the list of Zend modules to be loaded in.
Lastly, you have not provided the config you used, so I'm assuming you made a mistake there. Use something like the config below in your /config/autoload/database.local.php file. Technically you could split this over 2 files; a global and a local file. Local files are (/should) not be committed into version control history and as such can contain usernames and passwords. Any other config, such as using Pdo for a driver could go into global config.
'db' => [
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf3;hostname=localhost',
'username' => 'root',
'password' => 'root',
'driver_options' => [
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
],
],
I have a headless application written in yii, with an Angular application using the yii2 api. Currently im using local storage for tokens, but I read this link and would like to store the token in a cookie.
Auth action:
\Yii::$app->response->cookies->add(new Cookie([
'name' => 'token',
'value'=> $token->__toString()
]));
AuthMethod:
if (($cookie = $cookies->get('token')) !== null) {
die('Token found in cookie');
$token = $parser->parse($cookie->value);
}
The token is allways null, so it seems like cookies are disabled by default in Rest controllers / JSON responses, how can I enable this?
For furture reference, if the link is dead it concludes that cookies are better than local storage for JWT tokens
Cookies, when used with the HttpOnly cookie flag, are not accessible through JavaScript, and are immune to XSS. You can also set the Secure cookie flag to guarantee the cookie is only sent over HTTPS. This is one of the main reasons that cookies have been leveraged in the past to store tokens or session data. Modern developers are hesitant to use cookies because they traditionally required state to be stored on the server, thus breaking RESTful best practices. Cookies as a storage mechanism do not require state to be stored on the server if you are storing a JWT in the cookie. This is because the JWT encapsulates everything the server needs to serve the request.
EDIT
Using the native PHP $_COOKIE the cookie can be read by the yii2 application, but the setcookie() does not work. It looks like the yii2-rest controller strips away the headers before sending the response.
I will make my first attempt to answer and I hope it makes sense and helps you and others.
I asked you about angular version, because, as you know angular works as a one page app, and I will need proof of concept code to show my point «I will asume angularjs 1.6.x», it means it works away from your YII2, unless you are rendering angular on call. Now there are two ways to “bypass” this in order to set up the cookie.
The first one will be to set up your cookie inside angular, on your controller call your login endpoint and make it return the token (in my example I am not doing that part just for speed). And then build the cookie using the $cookie service «you will have to import angular-cookie».
The other way could be to call and endpoint inside Yii «look at the actionSetCookie example» and build the cookie inside it, I don't like that one that much looks dirty to me.
Now here comes the big problem, you may have, yii uses a cookie validation that “signs the cookie”, but when you build the cookie outside, this cookie will not work. So… to make this example work you will have to turn off cookie validation.
components' => [
'request' => [
'enableCookieValidation' => false, //<---make it false
'enableCsrfValidation' => true,
'cookieValidationKey' => 'hdfghdsrthrgfdhfghthdrtth',
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
...
]
Now, I made a working test.
First I made two simple action to test that I was actually building the cookie. And that I was able to call them with postman.
public function actionSetCookie()
{
Yii::$app->response->format = Response::FORMAT_JSON;
$session = Yii::$app->session;
$cookies_rsp = Yii::$app->response->cookies;
$cookies_rsp->add(new Cookie([
'name' => 'token',
'value' => 'tt-eyJhbGciOiJIUzI1NiIs...',
]));
$response = ['cookie set'=>$cookies_rsp];
return $response;
}
public function actionCookie()
{
Yii::$app->response->format = Response::FORMAT_JSON;
$session = Yii::$app->session;
$cookies = Yii::$app->request->cookies;
$token = '';
if (isset($cookies['token'])) {
$token = $cookies['token']->value;
}
$response = ['token'=>$token];
return $response;
}
And I made two controllers in angular to make the explanation:
.controller('View1Ctrl', ['$cookies', function ($cookies) {
console.log('View1Ctrl++++++++');
var vm = this;
vm.title = 'Customers';
$cookies.remove('token');
$cookies.put('token', 'my-angular-token');
vm.myToken = $cookies.get('token');
console.log('myToken', vm.myToken);
}
.controller('View2Ctrl', ['$http', function ($http) {
console.log('View2Ctrl');
//Lest set the cookie
$http({
method: 'GET',
url: 'http://test.dev/site/set-cookie'
}).then(function successCallback(response) {
console.log('response', response);
}, function errorCallback(response) {
console.error('err', response)
});
}
Now here it goes
On solution 1 «View1Ctrl», I build the cookie using the $cookie service, and I can validate it using action actionCookie, this will be read only if enableCookieValidation is false.
On the solution 2 «View2Ctrl», I am using the actionSetCookie as a http get endpoint that does not much, but sets the cookie, this cookie will work with enableCookieValidation false or true.
Conclusión
Remember that angular and yii2 are "supposed" to be agnostic and independent, so you will have to consume yii as endpoint.
You will have to se the enableCookieValidation, depending on your solution. I am not sure if there is a way to do it with angular but probably is not a good idea because you will have to publish the cookieValidationKey inside angular.
I don't like using cookies for apis, personally, because the idea of stateless and cookieless will help if your are developing a mobile app «I might be wrong about that».
About postman, it will work with solution 2 unless you turn off enableCookieValidation. Remember that this validation will add some salt to the token inside a cookie, that is yii additional security.
Finally on p[ostman, if enableCookieValidation is set to true and toy are manually making the cookie, Yii will not receive the cookie, because of security.
Just to illustrate this security related to the signing of cookies, I captured this video. I hope this will help. So this is because CookieValidation is true. This is a reason no to use the PHP default cookie service but tu use the one that Yii provides. On the video you will see how this system very specific for each cookie. ANd why you may not see the cookie in postman.
If you make CookieValidation false, this manual cookies, php default cookies will actually work again, but is less secure.
Video
About the discussion on the blog and Angular, remember that angular actually protects your app when using $http calls, it is very secure in that sense, but also don't forget to use ngSanitize on your app.
More on this:
https://docs.angularjs.org/api/ng/service/$http#cross-site-request-forgery-xsrf-protection
https://docs.angularjs.org/api/ngSanitize
https://docs.angularjs.org/api/ngCookies/service/$cookies
Finally, if I find something on securing the cookie like Yii2 does from angular I will add that to the post.
Hope it helps.
Just in case you like to look at my code
https://github.com/moplin/testdev
If you want to access cookies on server side so you have to send them as well in your request. Angular by default does not send cookies in XHR request. To enable cookies in request add this following code:
.config(function ($httpProvider) {
$httpProvider.defaults.withCredentials = true;
});
OR
$http.get("URL", { withCredentials: true })
.success(function(data, status, headers, config) {})
.error(function(data, status, headers, config) {});
See Usage section in angular $http
Make sure you also setting that cookie on client side, using javascript and then check in your chrome console for http request making sure it's also sending cookie in it.
Make sure you read cookies from $cookies = Yii::$app->request->cookies;
http://www.yiiframework.com/doc-2.0/guide-runtime-sessions-cookies.html#reading-cookies
And writing a cookie using $cookies = Yii::$app->response->cookies;
http://www.yiiframework.com/doc-2.0/guide-runtime-sessions-cookies.html#sending-cookies
If the token is an access token you could you use in REST controller
the autheticator behaviors
yii\filters\auth\HttpBasicAuth;
yii\filters\auth\HttpBearerAuth;
yii\filters\auth\QueryParamAuth;
and when received first time token to save it to a cookie in the browser from angular
Even if I configure CookieStore with:
MyApp::Application.config.session_store :cookie_store, {
key: '_myapp_session',
cookie_only: false,
httponly: false
}
and I make a POST request with
_myapp_session = #SOME_SESSION_ID
and authenticity_token = #AUTH_TOKEN
and http-header[X-CSRF-Token] set to #AUTH_TOKEN
finally the user is not authenticated, and new session is created with new AUTH_TOKEN and session id.
Can anybody give me some suggestions ?
Unfortunately there is NO SUPPORT for this option in current 4.0 branch. Although this option is forced to TRUE and I didn't find any code in rails sources using this option.
The way to make isolated POST's requests working is to create dedicated middleware, which will add appropriate session cookie. It must be inserted in the apropriate place, because middleware's order is significant.
Because it is very dangerous in CSRF security aspect, we must add to our middleware same verification, which will limit potential risk to minimum.