Mục lục

  • CSRF là gì?
  • Restful là gì? Các method cơ bản của của một Resource Controller
  • Sự khác biệt giữa Query Builder và Eloquent. Chúng có quan hệ gì với nhau?
  • Thế nào là Eager Loading
  • Scope
  • Accessors & Mutators
  • Middleware
  • Localization
  • Authorization (Access Control List)
  • Mail
  • Schedule
  • Event
  • Job
  • Inversion Of Control
  • Service Provider
  • Contracts
  • Facade

Nội dung

CSRF là gì?

1. Khái niệm

CSRF (Cross Site Request Forgery) là kĩ thuật tấn công bằng cách sử dụng quyền chứng thực của người sử dụng đối với 1 website khác. Các ứng dụng web hoạt động theo cơ chế nhận các câu lệnh HTTP từ người sử dụng, sau đó thực thi các câu lệnh này.

Hacker sử dụng phương pháp CSRF để lừa trình duyệt của người dùng gửi đi các câu lệnh http đến các ứng dụng web. Trong trường hợp phiên làm việc của người dùng chưa hết hiệu lực thì các câu lệnh trên sẽ được thực hiện với quyền chứng thực của người sử dụng.

CSRF còn dc gọi là "session riding", "XSRF"

2. Kịch bản tấn công CSRF

Người dùng Alie duyệt qua 1 diễn đàn yêu thích của mình như thường lệ. Một người dùng khác, Bob đăng tải 1 thông điệp lên diễn đàn. Giả sử rằng Bob có ý đồ không tốt và anh ta muốn lấy tiền từ những người có tài khoản tại ngân hàng như Bob. Alie sẽ tạo 1 thông báo, trong đó có chèn 1 đoạn code như sau:

eBank vừa công bố lãi xuất mới...
<img height=0″ width="0″ src="http://eBank.com/withdraw?account=bob_id&amount=1000000&for=Alie_ id"/>

Đoạn mã trên được che giấu rất khéo léo, thứ nhất nó thêm các thông điệp bình thường để người dùng không chú ý. Thứ hai thẻ <img sử dụng trong trường hợp này có kích thước 0x0 pixel và người dùng sẽ không thể thấy được. Giả sử Alie vừa mới truy cập vào tài khoản ngân hàng của mình và chưa thực hiện logout để kết thúc. Trình duyệt của Bob sẽ gửi câu lệnh HTTP GET đến địa chỉ lưu trong thẻ <img trong đoạn mã trên và nó sẽ dc thực hiện bằng quyền chứng thực của Bob.

Trong ví dụ trên hacker có thể sử dụng 1 URL khác.

Ví dụ: http://www.projectpage.com/admin/project/13/delete để xóa đi một dự án quan trọng nào đó mà Bob đang làm.

Một chú ý là hacker cần phải có 1 chút kĩ thuật về Social Engineering để có thể biết được nạn nhân sử dụng tài khoản ngân hàng nào, account của dịch vụ nào và forum thường hay vào là gì.

Ngoài thẻ <img, các thẻ html có thể sử dụng kĩ thuật trên có thể là:

<iframe height="0" width="0" src="http://eBank.com/withdraw? account=bob_id&amount=1000000&for=Alie_ id"/></iframe>
<link ref="stylesheet" href="http://eBank.com/withdraw?account=bob_id&amount=1000000&for=Alie_ id" type="text/css"/>
<bgsound src="http://eBank.com/withdraw?account=bob_id&amount=1000000&for=Alie_ id"/>
<background src="http://eBank.com/withdraw?account=bob_id&amount=1000000&for=Alie_ id"/>
<script type="text/javascript" src="http://eBank.comwithdraw?account=bob_id&amount=1000000&for=Alie_ id"/>

Các kĩ thuật CSRF rất đa dạng, lừa người dùng click vào link, gửi email chứa các đoạn mã độc đến người dùng… Hacker còn có thể che giấu các link ở trên rất khéo léo. Ví dụ trong trường hợp thẻ img, người dùng có thể nhận ra nếu vào đường link chứa trong <img src="http://eBank.com/withdraw?account=bob_id&amount=1000000&for=Alie_ id"/> Tuy nhiên, người dùng sẽ rất có phát hiện nếu hacker dùng đường link như sau: <img height="0" width="0" src="http://www.ahackersite.com/abc.jpg"/> và cấu hình lại máy chủ: Redirect 302/abc.jpg http://eBank.com/withdraw?account=bob_id&amount=1000000&for= Alie_ id. Như vậy người dùng sẽ rất khó để có thể phát hiện, vấn đề trách nhiệm phần lớn thuộc về các website của các nhà cung cấp.

3. Cách phòng tránh

Đối với người sử dụng internet

Để phòng tránh trở thành nạn nhân của các cuộc tấn công CSRF, người dùng internet nên thực hiện một số lưu ý sau

  • Nên thoát khỏi các website quan trọng: Tài khoản ngân hàng, thanh toán trực tuyến, các mạng xã hội, gmail, yahoo… khi đã thực hiện xong giao dịch hay các công việc cần làm.
  • Không nên click vào các đường dẫn không rõ nguồn gốc mà bạn nhận được qua email, qua facebook... Khi bạn đưa chuột qua 1 đường dẫn, phía dưới bên trái của trình duyệt thường có địa chỉ website đích, bạn nên lưu ý để đến đúng trang mình muốn.
  • Không lưu các thông tin về mật khẩu tại trình duyệt của mình (không nên chọn các phương thức "đăng nhập lần sau", "lưu mật khẩu", "ghi nhớ đăng nhập",...
  • Trong quá trình thực hiện giao dịch hay vào các website quan trọng không nên vào các website khác, có thể chứa các mã khai thác của kẻ tấn công.

Đối với các website

Có nhiều lời khuyến cáo được đưa ra, tuy nhiên cho đến nay vẫn chưa có biện pháp nào có thể phòng chống triệt để CSRF. Sau đây là một vài kĩ thuật sử dụng.

  • Hạn chế thời gian hiệu lực của SESSION Tùy theo ngôn ngữ hoặc web server dc sử dụng mà cách thực hiện có thể rất khác nhau. Với PHP, thông số session.gc_maxlifetime trong file php.ini quy định thời gian hiệu lực của session.
  • Lựa chọn việc sử dụng GET VÀ POST: Phương thức GET dc dùng để truy vấn dữ liệu, đối với các thao tác tạo ra sự thay đổi hệ thống thì các phương thức khác như POST hay PUT sẽ dc sử dụng
  • Sử dụng captcha, các thông báo xác nhận: Captcha được sử dụng để nhận biết đối tượng đang thao tác với hệ thống là con người hay không? Các thao tác quan trọng như "đăng nhập" hay là "chuyển khoản" ,"thanh toán" thường là hay sử dụng captcha. Tuy nhiên, việc sử dụng captcha có thể gây khó khăn cho một vài đối tượng người dùng và làm họ khó chịu. Các thông báo xác nhận cũng thường được sử dụng, ví dụ như việc hiển thị một thông báo xác nhận "bạn có muốn xóa hay không" cũng làm hạn chế các kĩ thuật tấn công này.
  • Sử dụng token: Tạo ra một token tương ứng với mỗi form, token này sẽ là duy nhất đối với mỗi form và thường thì hàm tạo ra token này sẽ nhận đối số là SESSION hoặc được lưu thông tin trong SESSION. Khi nhận lệnh HTTP POST về, hệ thống sẽ thực hiên so khớp giá trị token này để quyết định có thực hiện hay không. Một số framework hiện nay như là: laravel, aspnet webform,ruby on rails,django, Yii... đã hộ trợ tự động cơ chế token này.
  • Sử dụng cookie riêng biệt cho trang quản trị: Một cookie không thể dùng chung cho các domain khác nhau, chính vì vậy việc sử dụng admin.site.com thay vì sử dụng site.com/admin là an toàn hơn.
  • Kiểm tra REFERRER: Kiểm tra xem các câu lệnh http gửi đến hệ thống xuất phát từ đâu. Một ứng dụng web có thể hạn chế chỉ thực hiện các lệnh http gửi đến từ các trang đã được chứng thực.
  • Kiểm tra IP: Một số hệ thống quan trọng chỉ cho truy cập từ những IP dc thiết lập sẵn

Restful trong laravel

1. Khái niệm

REST là viết tắt của cụm từ Representational State Transfer (đôi khi còn được viết là ReST) là một kiểu kiến trúc được sử dụng trong việc giao tiếp giữa các máy tính (máy tính cá nhân và máy chủ của trang web) trong việc quản lý các tài nguyên trên internet. REST được sử dụng rất nhiều trong việc phát triển các ứng dụng Web Services sử dụng giao thức HTTP trong giao tiếp thông qua mạng internet. Các ứng dụng sử dụng kiến trúc REST này thì sẽ được gọi là ứng dụng phát triển theo kiểu RESTful.

2. Các method cơ bản của của một Resource Controller

Các method cơ bản của của một Resource Controller: index, create, store, show, edit, update, destroy

Resource Controller.PNG

Query Builder và Eloquent

1. Khái niệm

Query Builder cung cấp 1 giao diện thuận tiện và dễ dàng tạo và chạy những truy vấn từ database. Nó có thể được sử dụng để thực thi hầu hết những thao tác về database trong ứng dụng của bạn và làm việc với tất cả những database được hỗ trợ.

Eloquent ORM đi kèm với Laravel cung cấp ActiveRecord đầy đủ, đẹp đẽ và đơn giản để làm việc với database. Mỗi bảng của database sẽ được ánh xạ qua 'Model', và model này được sử dụng để tương tác với bảng.

Eloquent ORM là bản mở rộng từ Query Builder.

2. So sánh

  • Query Builder
    • Sử dụng thao tác trực tiếp với bảng
    • Câu lệnh phức tạp hơn
    • Có thể thực hiện các truy vấn phức tạp
    • Tốc độ thực hiện truy vấn nhanh
  • Eloquent ORM
    • Để sử dụng được Eloquent ORM cần phải tạo thêm Eloquent model trong thư mục app. Mỗi Eloquent model này đều phải extend Illuminate\Database\Eloquent\Model class.
    • Câu lệnh ngắn gọn đẹp hơn. Thêm 1 số tính năng softDelele, các scope, và các event boot.
    • Việc thực hiện truy vấn phức tạp khó khăn hơn nhưng có thể dùng Query Builder thay thế.
    • Tốc độ thực hiện truy vấn chậm hơn Query Builder, nhất là ở những truy vấn cần thao tác với dữ liệu lớn.

Eager Loading

Eager Loading là kĩ thuật để giải quyết bài toán N+1.

Ví dụ: Ta muốn load tất cả các products. Sau đó in ra tất cả từng category của từng product (giả sử mỗi product chỉ thuộc duy nhất 1 category và category có kết nối với product trong model). Ta làm như sau:

$products = Product::all();
for ($product : $products) {
  echo $product->category->name;
}

Nhìn vào đoạn code trên, có vẻ như là ổn. Tuy nhiên nếu xét về hiệu năng, thì điều đó thật tệ. Với N product, ta sẽ phải thực hiện tất cả N+1 query để get tất cả product và category tương ứng.

Để thực hiện yêu cầu trên trong laravel ta chỉ cần viết:

$products = Product::with('category')->get();

Ở cách này chỉ thực hiện 2 câu truy vấn:

select * from product
select * from category where id in (1, 2, 3, 4, 5, ...)

Như vậy Eager Loading sẽ giúp hiệu năng của ứng dụng web tăng lên đáng kể.

Scope

Scope trong laravel giúp tái sử dụng các câu truy vấn. Nếu bạn có 1 câu truy vấn thường xuyên sử dụng thì có thể tạo phương thức scope để có thể sử dụng được nhiều lần.

Ví dụ: Việc lấy người dùng đã active phải sử dụng nhiều lần nên ta dùng scope cho truy vấn này.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

Để lấy người dùng có lượt vote lớn hơn 100, ta sử dụng câu lệnh:

$users = User::active()->where('votes', '>', 100)->get();

Truyền param vào Scope

Để truyền param vào scope ta chỉ cần truyền thêm param vào phương thức Scope.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function scopeRole($query, $type)
    {
        return $query->where('role', $type);
    }
}

Sử dụng: $users = App\User::role('admin')->get();

Accessors & Mutators

Accessors và Mutators cho phép bạn thay đổi lại giá trị các thuộc tính của Eloquent khi lấy ra từ một model hoặc khi set giá trị cho nó. Ví dụ bạn muốn mã hóa dữ liệu trước khi lưu vào database và sau đó là giải mã khi lấy ra.

1. Accessor

Accessor bản chất là một phương thức được tự động gọi bởi Eloquent khi truy cập giá trị của column.

Ví dụ tạo Accessor cho cột first_name:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function getFirstNameAttribute($value)
    {
        return ucfirst($value);
    }
}

2. Mutator

Ngược lại với Accessor chính là Mutator. Phương thức Mutator sẽ được tự động gọi bởi Eloquent khi gán giá trị cho column.

Ví dụ tạo mutator cho cột first_name:

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function setFirstNameAttribute($value)
    {
        $this->attributes['first_name'] = strtolower($value);
    }
}

Middleware

1. Khái niệm, đặc điểm

Middleware là phần nằm giữa client và server, xử lý các request/response vào/ra server của client.

2. Sử dụng trong laravel

Trong laravel có 2 loại Middleware: Before Middleware và After Middleware

Before Middleware

  • Khai báo:
<?php

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // Perform action

        return $next($request);
    }
}
  • Cách dùng: Dùng trong trường hợp kiểm tra request đến.

  • Ví dụ: Kiểm tra nếu người dùng đủ 18 tuổi thì mới cho truy cập trang. Không thì sẽ chuyển hướng đến trang chủ.

<?php

namespace App\Http\Middleware;

use Closure;

class CheckAge
{
    public function handle($request, Closure $next)
    {
        if ($request->age <= 18) {
            return redirect('home');
        }

        return $next($request);
    }

}

After Middleware

  • Khai báo:
<?php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // Perform action

        return $response;
    }
}
  • Cách dùng: Dùng trong trường hợp gắn thêm kết quả trả về sau khi request được xử lý xong.

Đăng ký middleware

Sau khi khai báo xong, ta có thể đăng kí Middleware ở file app/Http/Kernel.php. Thêm middleware mới vào mảng routeMiddleware để có thể sử dụng được.

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'admin' => \App\Http\Middleware\Admin::class,
];

Localization

Chức năng localization của Laravel cung cấp một cách tiện lợi cho việc lấy các chuỗi dữ liệu từ các ngôn ngữ khác nhau, cho phép ứng dụng hỗ trợ đa ngôn ngữ.

Các chuỗi ngôn ngữ được lưu trong file nằm trong thư mục resources/lang. Trong thư mục này có chứa các thư mục con cho mỗi ngôn ngữ được hỗ trợ bởi ứng dụng:

Tất cả các file ngôn ngữ đơn giản chỉ cần trả về mảng các chuỗi khoá. Ví dụ:

<?php

return [
    'welcome' => 'Welcome to our application'
];

Ngôn ngữ mặc định được thiết lập trong file cấu hình config/app.php.

Có thể thay đổi ngôn ngữ sử dụng mặc định bằng cách sử dụng hàm setLocale của App facade: App::setLocale($locale)

Bạn có thể lấy các dòng trong file ngôn ngữ bằng cách sử dụng trans helper: trans('<file_name>.<key_name>'); hoặc sử dụng Blade @lang('<file_name>.<key_name>')

Truyền tham số vào chuỗi ngôn ngữ: Sử dụng :param để quy định tên biến cần truyền vào

Nội dung file message.php

<?php

return [
    'welcome': 'Welcome :name',
];

Sử dụng: trans('message.welcome', ['name' => 'HOI'])

Authorization

Laravel cũng cung cấp Authorization để tổ chức cấp quyền và điều khiển việc truy cập vào tài nguyên.

Có 2 cách để authorize trong laravel: Gates và Policies.

Gates

Gates chủ yếu dùng cho việc authorize các action riêng lẻ. Ta sẽ định nghĩa các rule trong method boot của AuthServiceProvider, sử dụng facade Gate.

Ví dụ: Ta muốn chỉ user là chủ của bài post mới có khả năng sửa bài post đó:

public function boot()
{
    $this->registerPolicies();

    Gate::define('update', function ($user, $post) {
        return $user->id == $post->user_id;
    });
}

Sau khi define xong ta có thể sử dụng bằng cách gọi lệnh allow hoặc deny.

if (Gate::allows('update', $post)) {
    // The current user can update the post...
}

if (Gate::denies('update', $post)) {
    // The current user can't update the post...
}

Mặc định Gates sẽ truyền vào user hiện tại. Để kiểm tra user khác thì ta sử dụng forUser

if (Gate::forUser($user)->allows('update', $post)) {
    // The user can update the post...
}

if (Gate::forUser($user)->denies('update', $post)) {
    // The user can't update the post...
}

if (Auth::user()->can('update', $post)){
    // The user can update the post...
}

Policies

Policies Class sẽ định nghĩa các rule liên quan tới 1 model hoặc resource cụ thể nào đó.

Ví dụ: Tạo 1 PostPolicy tương ứng với model Post để quản lý quyền cơ bản "CRUD" cho user.

php artisan make:policy PostPolicy --model=Post

Sau khi thực hiện lênh trên, laravel sẽ tạo 1 lớp PostPolicy với 4 method cơ bản: view, create, update và delete.

Bây giờ chỉ cho tác giả của bài viết mới được update bài viết ta sẽ sửa phương thức update như sau.

public function update(User $user, Post $post) {
    return $user->id = $post->user_id;
}

Để model Post sử dụng được ta phải đăng kí Policies trong file AuthServiceProvider.

<?php

namespace App\Providers;

use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Post::class => PostPolicy::class,
    ];

    public function boot()
    {
        $this->registerPolicies();
    }
}

Để kiểm tra xem user có quyền update post không thì sử dụng như lúc dùng Gate.

Chú ý: Policies sẽ có độ ưu tiên cao hơn Gate. Khi không tìm được rule phù hợp trong Policices thì laravel mới tìm trong Gate.

Tham khảo