pengantar
Dalam banyak kasus, kerentanan keamanan hanya muncul dari kurangnya kesadaran, bukan kelalaian. Meskipun kami menemukan bahwa sebagian besar pengembang peduli dengan keamanan, terkadang mereka tidak memahami bagaimana pola kode tertentu dapat menyebabkan kerentanan, jadi dalam eBook kami memutuskan untuk membagikan masalah keamanan paling umum yang pernah kami lihat saat membantu berbagai startup untuk melindungi aplikasi mereka. Laravel. Dengan setiap contoh serangan, kami juga akan menunjukkan kepada Anda praktik terbaik untuk melindungi aplikasi Anda dari serangan. Kami berharap informasi ini bermanfaat bagi Anda dan tim pengembangan Anda.
Tim CyberPanda
Injeksi SQL
Laravel menyediakan Query Builder dan ORM yang fasih. Dan, berkat mereka, sebagian besar permintaan dilindungi dalam aplikasi secara default, oleh karena itu, misalnya, permintaan seperti
Product::where('category_id', $request->get('categoryId'))->get();akan dilindungi secara otomatis karena Laravel akan menerjemahkan kode tersebut ke dalam pernyataan yang telah disiapkan dan dieksekusi.
Tetapi para pengembang biasanya membuat kesalahan dengan mempercayai bahwa Laravel melindungi dari semua injeksi SQL, meskipun ada beberapa vektor serangan yang tidak dapat dilindungi oleh Laravel.
Berikut adalah alasan injeksi SQL paling umum yang pernah kami lihat di aplikasi Laravel modern selama audit keamanan kami.
1. Injeksi persegi melalui nama kolom
, , , Laravel , Query Builder Eloquent. , , , , .
PDO does not support binding column names. Therefore, you should never allow user input to dictate the column names referenced by your queries, including "order by" columns, etc. If you must allow the user to select certain columns to query against, always validate the column names against a white-list of allowed columns.
, SQL-:
$categoryId = $request->get('categoryId');
$orderBy = $request->get('orderBy');
Product::query()
->where('category_id', $categoryId)
->orderBy($orderBy)
->get(); - orderBy
http://example.com/users?orderBy=id->test"' ASC, IF((SELECT count(*)
FROM users ) < 10, SLEEP(20), SLEEP(0)) DESC -- "'SQL-:
select
*
from `users`
order by `id`->'$."test"' ASC,
IF((SELECT count(*) FROM users ) < 10, SLEEP(20), SLEEP(0))
DESC -- "'"' asc limit 26 offset 0, Laravel*, , , Laravel , Query Builder .
, SQL-, - , , .
, «users» - "secretAnswer", SQL-.
2. SQL-
$id = $request->route('id');
$rules = [
'username' => 'required|unique:users,name,' . $id,
];
$validator = Validator::make($request->post(), $rules); Laravel $id , SQL-. " " > "SQL-".
3. SQL-
, , , , DB::raw . , , - . DB::raw - , , DB::getPdo()->quote.
:
public function update(Request $request) {
$id = $request->route('id');
$rules = [
'username' => 'required|unique:users,username,' . $id,
];
$validator = Validator::make($request->post(), $rules);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
$user = User::findOrFail($id);
$user->fill($validator->validated());
$user->save();
return response()->json(['user' => $user]);
}
required|unique:users,username,'. $id? ! ()
, unique , . , $id , , . , , , .
1.
, - ID = 10|sometimes, required|unique:users,username,10|sometimes , - , .
2. DDOS REGEX
Regex ReDoS DDOS . , , , :
PUT /api/users/1,id,name,444|regex:%23(.*a){100}%23
{
"username": "aaaaa.....ALOT_OF_REPETED_As_aaaaaaaaaa"
}
3. SQL-
SQL- . :
PUT /api/users/1,id,name,444|unique:users,secret_col_name_here
{
"username": "secret_value_to_check"
} , unique ( PDO) SQL- . Laravel .
:
- , , ;
(ID ), , .
XSS ( ) Laravel Blade
XSS 1990- , , - , , . , , XSS- :
Some text
<input onfocus='$.post("/admin/users", {name:"MaliciousUser", email:
"MaliciousUser@example.com", password: "test123", });' autofocus />
test
- . IP- , , /.
, XSS- Laravel.
Laravel Blade, XSS-, , :
// $name = 'John Doe <script>alert("xss");</script>';
<div class="user-card">
<div> ... </div>
<div>{{ $name }}</div>
<div> ... </div>
</div>
Blade {{ }} . , :
<div class="user-card">
<div> ... </div>
<div>John Doe
<script>alert("xss");</script></div>
<div> ... </div>
</div>
XSS. Laravel ( ) , XSS-, :
1. XSS {!! $userBio !!}
, HTML, {!! !!}:
// $userBio = 'Hi, I am John Doe <script>alert("xss");</script>';
<div class="user-card">
<div> ... </div>
<div>{!! $userBio !!}</div>
<div> ... </div>
</div> Laravel , $userBio JavaScript , XSS-.
:
html , .
, HTML, , htmlpurifier.org, HTML JS .
2. XSS a.href
, , , , XSS-:
1: javascript:code
// $userWebsite = "javascript:alert('Hacked!');";
<a href="{!! $userWebsite !!}" >My Website</a>2: base64:
, .
// $userWebsite =
"data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGFja2VkISIpOzwvc2NyaXB0Pg
==";
<a href="{!! $userWebsite !!}" >My Website</a>(«Hacked!») , « -» ...
:
, . http/https ;
, http/https «#broken-link».
3. XSS
Blade , , HTML. , , , Laravel :
// Registering the directive code
Blade::directive('hello', function ($name) {
return "<?php echo 'Hello ' . $name; ?>";
});
// user.blade.php file
// $name = 'John Doe <script>alert("xss");</script>';
@hello($name);:
Laravel e(), , . 3 , Laravel . , XSS- Laravel, XSS-, , , React.js, Vue.js, javascript jQuery, XSS-.
Laravel
Eloquent, ORM, , . , , .
, , :
// app/Models/User.php file
class User extends Authenticatable
{
use SoftDeletes;
const ROLE_USER = 'user';
const ROLE_ADMINISTRATOR = 'administrator';
protected $fillable = ['name', 'email', 'password', 'role'];
// ... rest of the code ...
}
// app/Http/Requests/StoreUserRequest.php file
class StoreUserRequest extends Request
{
public function rules()
{
return [
'name' => 'string|required',
'email' => 'email|required',
'password' => 'string|required|min:6',
'confirm_password' => 'same:password',
];
}
}// app/Controllers/UserController.php file
class UserController extends Controller
{
public function store(StoreUserRequest $request)
{
$user = new User();
$user->role = User::ROLE_USER;
$user->fill($request->all());
$user->save();
return response()->json([
'success' => true,
],201);
}
// ... rest of the code ...
}, , - , , .
{
"name" : "Hacker",
"email" : "hacker@example.com",
"role" : "administrator",
"password" : "some_random_password",
"confirm_password" : "some_random_password"
} "role" $fillable. "role" , . , , , API, - , Laravel, . $fillable , , , API, ACL.
, Laravel.
:
1.
, , . , . "name", "email" "password". Laravel $request->validated(), .
, $request->all() $request->validated() :
public function store(StoreUserRequest $request)
{
$user = new User();
$user->role = User::ROLE_USER;
$user->fill($request->validated());
$user->save();
return response()->json([
'success' => true,
],201);
} Laravel, $request->validate() $validator->validated(), .
, , , .
2.
$fillable ( , ) $guarded ( , ), $guarded, .
3. . $model->forceFill($data)
$model->forceFill , $forceFill $fillable . forceFill, , .
, , ? , , . , , / . , , , 0,1-0,2% . , - 1 , 10 , 10'000-20'000 . , .
- , .
- Laravel Auth , , IP- , . , :
1.
, . Symantec , 80% 2FA.
2. IP-
, IP, .
3.
IP, 100% , .
4. , /
FaceBook, - , :

5.
, , .
, Laravel, SQL- XSS, , ACL . ACL - , .
HTTP
- HTTP (HTTP Strict Transport Security, X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, , . .), . HTTP . , HTTP Strict Transport Security HTTPS ( , HTTP HTTPS ). X-Frame-Options .
Laravel, . , , ? , , , , , .
Laravel , . , :
. , , 700 Equifax. , Equifax Apache Struts, 2 . Equifax 147,9 .
Laravel , , , , .
Laravel - , - - . , Laravel, API (, Eloquent), , Laravel , .
, , , , :
. , {{$userBio}} {!!$userBio!!}.
* "Vektor serangan telah diperbaiki dalam versi terbaru Laravel" - menurut artikel aslinya, tanggal rilisnya tidak jelas, serta dari situs web mereka, sehingga tidak mungkin untuk menetapkan versi Laravel mana yang terbaru pada saat itu. Namun demikian, artikel itu sampai ke tangan pada hari penerjemahan, dan pada saat itu Laravel 8 ada selama beberapa hari.