我正在使用CI 4构建一个Web应用程序沿着Android API。
对于Web应用程序,我有一个过滤器来检查用户是否已经登录,但有一些例外,其中之一是如果URL包含api/*(API的URL是http://localip/api/),则忽略过滤器
如果请求方法是GET,API工作正常。我可以从API获取数据。但当我尝试使用POST方法将数据插入数据库时,它会将我重定向到登录页面(我正在使用Postman测试API)
我该如何解决这个问题?
到目前为止,我所尝试的是将登录筛选器别名添加到
public $methods = [
'post' => ['csrf', 'loginfilter']
]; But still not working
下面是完整的代码
过滤器.php
<?php
namespace Config;
use App\Filters\CorsFilter;
use App\Filters\LoginFilter;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Filters\CSRF;
use CodeIgniter\Filters\DebugToolbar;
use CodeIgniter\Filters\Honeypot;
use CodeIgniter\Filters\InvalidChars;
use CodeIgniter\Filters\SecureHeaders;
class Filters extends BaseConfig
{
/**
* Configures aliases for Filter classes to
* make reading things nicer and simpler.
*
* @var array
*/
public $aliases = [
'loginfilter' => LoginFilter::class,
'cors' => CorsFilter::class
];
/**
* List of filter aliases that are always
* applied before and after every request.
*
* @var array
*/
public $globals = [
'before' => [
// 'honeypot',
'csrf',
'loginfilter' => ['except' => ['/', '/login', 'api/*']],
'cors'
// 'invalidchars',
],
'after' => [
'toolbar',
// 'honeypot',
// 'secureheaders',
],
];
/**
* List of filter aliases that works on a
* particular HTTP method (GET, POST, etc.).
*
* Example:
* 'post' => ['csrf', 'throttle']
*
* @var array
*/
public $methods = [
'post' => ['csrf','loginfilter]
];
/**
* List of filter aliases that should run on any
* before or after URI patterns.
*
* Example:
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
*
* @var array
*/
public $filters = [];
}
登录过滤器.php
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class LoginFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
$session = session();
if (!$session->has('user_id')) {
return redirect()->to(base_url() . '/');
}
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
}
}
路由.php
$routes->resource("api/role", ['controller' => 'apis\MasterDataRoleApi']);
主数据角色Api.php(控制器)
<?php
namespace App\Controllers\apis;
use App\Models\GeneralModels;
use App\Models\RoleModel;
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\RESTful\ResourceController;
class MasterDataRoleApi extends ResourceController
{
use ResponseTrait;
protected $model;
protected $generalModel;
public function __construct()
{
$this->model = new RoleModel();
$this->generalModel = new GeneralModels();
}
public function index()
{
$role= $this->request->getVar('role');
$data = $this->model->getRoleApi($role);
return $this->respond($data, 200);
}
public function create()
{
$roleName = $this->request->getPost('role_name');
$supervisor = $this->request->getPost('supervisor');
$userId = $this->request->getVar("userId");
helper('idgenerator');
$maxCode = $this->generalModel->getMaxData('tmrole', 'role_id');
$generatedId = idGenerator($maxCode[0]['role_id'], 4, 3, "JAB-");
$this->model->insertTmRole($generatedId, $roleName, $userId, $userId);
$data = array();
$dataArr = array(
"response" => "Success",
"response_details" => "Saved Successfully"
);
$data[] = $dataArr;
return $this->respondCreated($data, 201);
}
}
下图显示了请求方法为GET https://i.stack.imgur.com/2ZKPd.png时返回的Json
下图显示了请求方法为POST https://i.stack.imgur.com/11R0z.png时返回的登录页面
先谢谢你了。
2条答案
按热度按时间sy5wg1nm1#
A部分:CSRF公司
说明1:
下图显示了请求方法为GET https://i.stack.imgur.com/2ZKPd.png时返回的Json
您的API
GET
请求工作正常,因为它们不受保护。跨站点请求伪造(CSRF)
CSRF保护仅适用于
POST
/PUT
/PATCH
/DELETE
请求。其他方法的请求不受保护。说明2:
下图显示了请求方法为POST https://i.stack.imgur.com/11R0z.png时返回的登录页面
错误
该错误来自system/Security/安全性.php::verify()
throw SecurityException::forDisallowedAction();
您通常会在两种情况下收到此错误:
1.当您忘记将CSRF令牌与请求沿着提交时(POST/PUT/etc.)。
1.当与HTML表单/请求正文沿着提交的CSRF令牌与CSRF Cookie中存在的令牌不匹配时。
打开CSRF筛选器后,当您发出HTTP请求但缺少CSRF Cookie时,系统会自动生成一个,并在HTTP
Set-Cookie: '...'
响应标头中发送。如果您使用的是默认基于Cookie的CSRF保护,则在发出任何进一步的(POST/PUT/etc.)请求时,您需要在提交请求时提交匹配的CSRF令牌。
双重提交Cookie
这种技术很容易实现,并且是无状态的。在这种技术中,我们在cookie中发送一个随机值,并将其作为请求参数,服务器验证cookie值和请求值是否匹配。当用户访问(甚至在认证之前阻止CSRF登录),该站点应生成(密码编译强度)伪随机值,并将其设定为使用者计算机上的Cookie,与工作阶段识别项分开。然后网站要求每个交易请求都包含这个伪随机值作为一个隐藏的表单值(或其他请求参数/报头)。如果两者在服务器端匹配,服务器将接受它作为合法请求,如果不匹配,则拒绝该请求。
CSRF解决方案:
要通过 * 双重提交Cookie* 测试,每次发出(POST/PUT/etc.)请求时,您都需要提交一个CSRF Cookie和一个具有匹配CSRF标记的请求参数/标头。即:
需求1:
Cookie: csrf_cookie_name=ccd8facfa8229bdba5e0160c108d1a02;
HTTP要求信头。要求2:
用户发送令牌的顺序
检查CSRF令牌可用性的顺序如下:
$_POST
阵列(即:<input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" />
)的数据。X-CSRF-TOKEN: ccd8facfa8229bdba5e0160c108d1a02
)的数据。php://input
(JSON请求)-请记住,这种方法是最慢的一种,因为我们必须解码JSON,然后重新编码它。(即:(一个月12个月1x个月)下面是我个人的
.env
文件配置,对我来说很有效。将 myapp.local 更改为应用程序的域。
.env
档案。与 * 安全性/CSRF、COOKIE、APP/会话 * 相关的其余
.env
文件配置保持其默认设置。在CSRF部分的最后,如果你仍然有问题,安装和配置Xdebug,在这个方法**system/Security/Security.php::verify()**中添加断点,并确认你的HTTP请求是否通过了那里的条件。确保你的Xdebug配置类似于:(
xdebug.log_level = 0 | xdebug.mode = debug,develop | xdebug.start_with_request = yes | xdebug.client_port = 9004 | xdebug.client_host = "localhost" | xdebug.trace_output_name = "trace.%c.%t-%s.%H_%R" | xdebug.profiler_output_name = "cachegrind.out.%t-%s.%H_%R" | xdebug.remote_handler = "dbgp" | xdebug.show_local_vars = 9
)B部分:或Insomnia
本节介绍如何设置REST API客户端应用程序工具,以便能够测试项目的端点。
HTTP请求标头要求:
X-Requested-With: XMLHttpRequest
个X-CSRF-TOKEN: 62b04a891414ef789bee7108f94ad97a
Content-Type: application/x-www-form-urlencoded
个Cookie: csrf_cookie_name=62b04a891414ef789bee7108f94ad97a; ci_session=4ji7amn186ckbo0gutdoe3ai6ufumk4e
User-Agent: insomnia/2022.1.1
Host: myapp.local
User-Agent
可以根据您使用的是一种工具还是另一种工具而变化(即失眠或 Postman )。Host
也会有所不同,具体取决于您如何设置应用程序的基本URL。Content-Type
可以根据您提交给服务器的数据类型而变化。(例如HTML FORM -〉application/x-www-form-urlencoded
和JSON -〉application/json
)。对于
Cookie
头,如果您的端点位于身份验证系统或登录过滤器之后,您可能需要附加ci_session
(session_id)cookie。当然,如果您的API使用不同的身份验证机制(即:此外,如果您的应用程序已启用csrf
筛选器,则可能需要附加如上所示的csrf_cookie_name
Cookie。在这种情况下,您可能希望创建一个专用的GET
API路由端点,专门用于接收csrf
Cookie名称和值(哈希)。或者,如果你懒得设置一个专门的端点来发送CSRF令牌,并且你已经运行了Web应用程序,在登录/浏览你的应用程序时打开浏览器的控制台,在应用程序选项卡-〉Cookie-〉你的域中,你应该能够在Postman / Insomnia中看到并使用这些Cookie。X-CSRF-TOKEN
HTTP请求标头值应与csrf_cookie_name
Cookie值相同。HTTP请求调用要求:
即:
x1米38英寸
csrf_cookie_name
标记添加为请求正文的一部分。*| 关键字|数值|
| - -|- -|
| 公司名称|特斯拉公司|
| csrf_cookie_名称|一种用于汽车的制动器|
我以 * 第B部分结束:*
| 重要事项|项目名称|
| - -|- -|
|
ci_session
Cookie***或***Authorization: Bearer xxxxxxx
HTTP请求标头。|允许您***仅***对受身份验证保护的API终结点使用应用程序/项目进行身份验证。在您的特定情况下,我相信您的loginfilter
正在使用ci_session
Cookie,并且该Cookie应该在Cookie
HTTP请求标头的帮助下随每个请求沿着发送。||
csrf_cookie_name
Cookie***和***(X-CSRF-TOKEN
HTTP请求标头***或***CSRF令牌请求参数)。|CSRF Cookie***和***(X-CSRF-TOKEN
HTTP请求标头*或*CSRF标记请求参数)值必须匹配。如果已打开csrf
过滤器,则这是必需的。|pgx2nnw82#
从我所看到的是,你有一个loginfilter作为每个POST方法的后备。这可能是罪魁祸首。
也就是说,这里有一个替代的解决方案。您可以在routes.php中对路由进行分组,并对这些路由应用
loginfilter
。此外,您还可以根据需要对它们进行嵌套和分区。示例:
您可以在使用此方法时删除全局筛选器。