2019-02-17

NOSQL có đồng nghĩa với NO Injection?

NOSQL có đồng nghĩa với NO Injection?


NOSQL có đồng nghĩa với NO Injection?


Chắc hẳn chúng ta đã khá quen thuộc với khái niệm SQL Injection đây là một lỗi hổng phổ biến nhất cũng như nguy hiểm nhất với các trang web trên Internet. "Gần đây" với sự phất triển của những loại database mới như graph database và NoSql đã làm phong phú hơn lựa chọn dataabase của các dự án phàn mềm.
Với những ưu điểm của mình như:
  • Mã nguồn mở
  • khả năng mở rộng linh hoạt
  • Phù hợp với điện toán đám mây và bigData.
các csld NoSql như MongoDb hay redis là những lựa chọn đáng để cân nhắc với những hệ thống lớn, những một khía cạnh có lẽ không được nhắc đến nhất là ở Việ Nam mình đó chính là tính bảo mật của những csld này, cuối tuần rảnh rỗi sinh nông nổi mình quyết định viết một bài để đánh giá tính bảo mật của csld NoSQL.
Trước khi bắt đầu để tránh gạch đá mình xin làm rõ một vắn để là bản thân CSLD chỉ là: "một tập hợp thông tin có cấu trúc. Tuy nhiên, thuật ngữ này thường dùng trong công nghệ thông tin và nó thường được hiểu rõ hơn dưới dạng một tập hợp liên kết các dữ liệu, thường đủ lớn để lưu trên một thiết bị lưu trữ như đĩa hay băng. Dữ liệu này được duy trì dưới dạng một tập hợp các tập tin trong hệ điều hành hay được lưu trữ trong các hệ quản trị cơ sở dữ liệu." vậy nên nếu vọi vàng đánh giá csld này an toàn csld kia không an toàn chưa hẳn đã chính xác mà một nhân tố vô cùng quan trọng nữa là hện quản trị CSDL (HQTCSDL) ta sử dụng cũng như driver mà ta sử dụng để giao tiếp với HQTCSDL, nội bài biết này mình sẽ giới thiệu một bài lỗ hổng thường gặp trong các HQTCSDL NoSQL., mà cụ thể là MongoDb HQTCCSDL NoSQL phổ biến nhất hiện nay.

Cơ Chế Hoạt Động

Ngay trên trang MongoDB Developer FAQ có nói:
"... with MongoDB we are not building queries from strings, so traditional SQL injection attacks are not a problem."
tức là MongoDb có thể tránh được tất cả các loại SQL injection truyển thống, thay vào đó các hacker lại sự dụng một ký thuật đặc thù cho NoSql đó là NoSQL Injection.

cũng như SQL injection để có thể thực hiện NoSQL Injection hacker cũng phải truy vấn lên server, dựa vào request từ client server sẽ truy vấn đến Database và nhận lại kết quả từ database để trả cho client. Nhiệm vụ của hacker là phải làm sao để hiểu sai request dẫn đến thực hiện một câu truy vấn không mong muốn đến database cuối cùng hacker sẽ lấy được thông tin mong mốn hoặc ngiêm trọng hơn là tthay đổi thậm chí là xóa dự liệu trong csdl.
điểm khác của NoSQL Injection so với SQL Injection truyển thống là:
  • câu truy vấn cho khối dữ liệu không cấu trúc.
  • các HQTCSDL rất đa dạng và khác biệ nhau khá nhiều trong cachs tổ chức dữ liệu cũng như truy vấn.
  • cho phép truy cập trực tiếp client-database thông qua RESTfull API.

Các Loại Tấn Công

có 3 loại tấn công **NoSQL Injection chủ yêu là:
  • Login bypass for MongoDB on PHP and NodeJS
  • String concatenation
  • Escaping flaws of drivers

1. LOGIN BYPASS

đây là loại tấn công rất nguy hiểm vì hacker có thể bỏ qua quy trình đăng nhập và giành quên một cách không mất khó khăn.

giả sử ta có một đoạn login sử dụng NodeJs - express.js - mongodb như sau:
// NodeJS with Express.js
db.collection('users').find({
"user": req.query.user,
"password": req.query.password
});
ở đây ta sử dụng luôn tham số trong request của client để thuwchj hiện câu truy vấn đên database. với dự đoán than số mà người dùng gửi lên sẽ dạng như này:
✔ https://example.org/login?user=patrick&password=1234
trong trường hợp này nếu ông hacker vui tính nào đó gửi lên một request dang như này thì chuyện gì sẽ sảy ra:
⚡ https://example.org/login?user=patrick&password[%24ne]=
khi đó câu query của chúng ta sẽ như thế này
// NodeJS with Express.js
db.collection('users').find({
"user": "patrick",
"password": {"&ne": ""}
});
serlector &ne (not equals) sẽ tìm những bản gì khong bằng giá trị "" tức là trường password sẽ luôn luôn true, hacker đã by pass thanh công.

2. String Concat

Tương tự như SQL Injection vấn đề nối chuỗi (string concat) vẫn là một vấn đề, nếu dev code cẩu thả thì hacker có thể lợi dụng để injectect những đoạn ký tự đặc biệt làm câu query bị thực thui sai mục địch.
vẫn là chức năng đăng nhập trên làn này ta chọn một cách cài đặt khác như sau:
// nodejs example
var string query = “{ username: ‘“ + user + “’, password: ‘” + password + “’ }”

một đoạn có trông có vẻ ngây thơ vô tội nhỉ? nhưng với hacker thì đây đúng là một cơ hội vàng.
⚡ https://example.org/login?username=admin’, $or: [ {}, { ‘a’:’a&password=’ } ], $comment:’hacked’
với request trên câu query của chúng ta sẽ biến thành thế này:

{ username: ‘tolkien’ , $or: [ {}, { ‘a’: ‘a’, password: ‘’ } ], $comment: ‘hacked’ }

OMG, một lần nữa chúng ta đã bypass được login với biểu thức toán tử $or : [true, false ] sex trar laij keets quar true :D
Ngoài ra còn khá nhiều kỹ thuật tấn công khác nếu hứng thú anh em có thể hỏi bác gut gồ nhé.

2019-02-11

[JAVASCRIPT] JavaScript hoạt động như thế nào?

[JAVASCRIPT] JavaScript hoạt động như thế nào?

1. Single Thread

  1. Làm một việc tại một thời điểm Không giống như đa số các ngôn ngữ lập trình khác, javascript đơn giản là đơn luồng. Điều này đồng nghĩa với việc tại một thời điểm nó chỉ xử lý duy nhất một việc. Bất cứ tác vụ nào đều phải thực hiện lần lượt, khi một tác vụ của bạn thực hiện quá lâu cũng tương ứng với việc trình duyệt sẽ chờ xử lý tác vụ đó xong mới thực thi các tác vụ tiếp.
  2. Mỗi tab hold một single thread Môi khi bạn mở thêm một tab mới trên trình duyệt, trình duyệt sẽ sinh ra một javascript single thread. các thread giữa các tab độc lập với nhau về logic xử lý. # 2. Heap And Stack
    Mỗi Single Thread javascript sẽ có một bộ nhớ heap và stack. Giống đại đa số các ngôn ngư lập trình khác, heap là nơi lưu trữ các dạng dữ liệu về object, còn stack là nơi lưu trữ dữ liệu trong quá trình thực thi code. Stack của javascript là một dạng LIFO data storage, nôm na có thể hiểu là nơi lưu trữ các hàm hay câu lệnh nào đang được thực thi. Các lệnh sẽ được push vào theo thứ tự vào sau cùng ra đầu tiền. NHững cái ô vàng vàng mà các bạn nhìn thấy trong hình vẽ được gọi là một stack frame. Nếu bất kì lời gọi nào tại frame hiện tại bị lỗi, javascript print stack trace ra console log của trình duyệt. function baz(){ throw new Error('Something went wrong.'); } function bar() { baz(); } function foo() { bar(); } foo();

3. Eventloop and callback queue

Eventloop và callback queue là 2 component khá thú vị của javascript.

Hãy hiểu đơn giản thế này, Bây giờ bạn có một tác vụ, đó là gửi một http-request để lấy thông tin từ một trang web nào đó chẳng hạn, và tác vụ này cần một thời gian dài cơ 1 phút để xử lý. Nếu như trình duyệt sử dụng cùng một thread xử lý javascript cho việc xử lý các tác vụ mang tính delay trên thì sẽ ảnh hưởng đến trải nghiệm người dùng vì họ phải đợi 1 phút để có thể tiếp tục sử dụng. Để tránh việc này, với những tác vụ mang tính delay, tức là đòi hỏi thời gian dài để xử lý, trình duyệt đã viết riêng các đoạn code xử lý đống ấy bằng một ngôn ngữ khác và cung cấp cho bạn api để gọi cái đống phức tạp ấy một cách rất sáng sủa. Ví dụ, setTimeout, setInterval, các tác vụ liên quan đến httpRequest v.v...
Đồng thời trong javascript runtime sẽ sinh ra thêm 2 component là eventloop và callback queue.
Callback queue ở đây là một queue chứa các hàm callback- thứ mà được ném vào cùng với lời gọi các api phức tạp ở trên.
Ví dụ:
setTimeout(function (){
console.log("this function is callback");
},3000);
Ở ví dụ trên cái funtion bên trong được gọi là callback, khi lời gọi hàm setTimeout được thì xong, thì hàm callback kia sẽ được đẩy vào callbackqueue.
Eventloop là thằng luôn luôn lắng nghe cái callback queue kia xem có thằng nào xuất hiện không thì bên nhấc nó ra thực thi lần lượt. Ở đây khi hàm callback được push vào callback queue thì thằng eventloop đang làm nhiệm vụ lắng nghe bống thấy một ông callback funtion được push vào, ngay lập tức, nó bê cái funtion callback đó ra stack để thực thi, và tiếp tục nhiệm vụ lắng nghe của mình.
Như vậy, về cơ bản, những component giúp javascript hoạt động m đã liệt kê ở trên

2019-01-24

Các câu hỏi hay gặp khi học OOP

Các câu hỏi hay gặp khi học OOP

Các câu hỏi hay gặp khi học OOP(Java)

Xin chào mọi người. Đây là bài viết đầu tiên của mình trên Kipalog nên sẽ có nhiều lỗi sai, mong mọi người chỉ giáo. Trong quá trình mình học về OOP trong Java thì cũng có những thắc mắc, mình xin phép được tổng hợp lại một số thắc mắc thường thấy khi bắt đầu nghiên cứu về OOP.

1. Abstract class khác Interface ở chỗ nào?

Đầu tiên thì phải định nghĩa lại hai khác niệm này đã:
  1. Abstract class: Đây là một Class cha dùng để định nghĩa về bản chất cho các Class con. Bản chất ở đây có thể hiểu là: loại, kiểu, nhiệm vụ, thuộc tính, ... của các Class. Hiểu nôm na là người con sẽ được kế thừa các đặc tình của người cha.
  2. Interface: Có thể hiểu đây là một dạng bảng thiết kế cho chức năng mà bất kỳ Class nào cũng có thể có. Một interface chứa các hành vi mà một class triển khai.
==> Điểm khác biệt đầu tiên có thể thấy là Abstract là một Class còn Interface thì không. Một Class có thể mô tả các thuộc tính và hành vi của một Object. Còn Interface lại chứa các hành vi mà một Class sẽ triển khai. Ngoài ra còn một số điểm khác biệt sau đây:
Abstract classInterface
Định nghĩa codeHỗ trợ định nghĩa cho các void, propertyKhông hỗ trợ định nghĩa mà chỉ cho khai báo
Về Access ModifiersCho phép xác định ModifierMặc định đều là public
Fields and ConstantsCó hỗ trợKhông hỗ trợ
Đa kế thừaKhông hỗ trợ, chỉ có thể extend 1 Abstract classCó hỗ trợ

2. Tại sao phải chia ra Abstract và Interface?

Như đã nói ở bên trên thì Interface có hỗ trợ đa kế thừa còn Abstract thì lại không. Ngoài ra thì còn một tác dụng nữa, bạn xem ví dụ sau nha:
Bài toán: Bạn cần phải tạo ra một vườn thú gồm có các con vật sau: Chó, Mèo, Chim và Cá. Mỗi loài vật đều có điểm chung như có tên, tiếng kêu nhưng cũng có điểm riêng như bơi, bay, chạy.
Vậy ta nên giải quyết vấn đề này như nào bây giờ? Chả nhẽ lại viết một Class Animal cha rồi ở mỗi Class con thì sẽ viết từng điểm riêng cho nó sao?
public abstract class Animal 
{
    public String name;
    public String sound;

    public Animal(String name, String sound) {
        this.name = name;
        this.sound = sound;
    }    
}

public class Cat extends Animal
{    
    private void iRun()
    {
        System.out.println(name + "run");
    }
    public Cat(String name, String sound) {
        super(name, sound);
    }    
}
...
Vậy thì dài quá :( Nhưng chúng ta hãy phân tích lại nhé :) Mỗi loài vật đều có những điểm chung cố định, vậy nên chúng ta sẽ cho nó vào 1 Abstract class. Còn các điểm riêng thì sao? Đây chính là lúc mà Interface phát huy tác dụng, nó dùng các chức năng mà :) Nên chúng ta có thể sử dụng chúng để thiết kế cho từng chức năng Chạy, Bơi, Bay, ... Rồi implements cho từng Class riêng biệt. Điều này cũng có thể giải quyết cho những loài vật có nhiều khả năng như cả chạy cả bay.
Chốt lại, bạn nên xác định rõ dùng Abstract hay Interface qua các điều kiện sau đây:
Abstract classInterface
  • Bạn muốn chia sẻ đoạn code trùng nhau với các class liên quan.
  • Bạn thấy các Class con có nhiều method , field giống nhau.
  • Bạn không cần sử dụng cơ chế multiple inheritance.
  • Các class không liên quan với nhau.
  • Bạn muốn tận dụng cơ thế multiple inheritance.

3. Tại sao nên khai báo <Lớp cha> = new <Lớp con>

Điều này được gọi là tính Đa Hình trong OOP.
Ví dụ ta có 1 Class Shape là class cha và 2 Class HinhTamGiac, HinhVuong là class con như sau:
public abstract class Shape 
{
    public abstract int tinhChuVi();
    public abstract void veHinh();
}
public class HinhTamGiac extends Shape
{
    @Override
    public int tinhChuVi() 
    {
        return 1;
        // Ở đây chỉ là ví dụ thôi
    }

    @Override
    public void veHinh() 
    {
        System.out.println("Tam Giac");
    }    
}
public class HinhVuong extends Shape
{
    @Override
    public int tinhChuVi() {
        return 2;
    }

    @Override
    public void veHinh() {
        System.out.println("Hinh Vuong");
    }    
}
Có phải nó rất dài không, tại sao lại phải viết thêm Class cha mà sao không viết hẳn luôn 2 class con ra ? :smile: Nhưng nếu bây giờ ta có một Class Controller nữa:
public class Controller 
{
    public static void main(String[] args) 
    {
        Shape[] list = new Shape[2];
        list[0] = new HinhTamGiac();
        list[1] = new HinhVuong();

        for(Shape shape : list)
        {
            printInfo(shape);
        }
    }
    public static void printInfo(Shape shape)
    {
        System.out.println("Chu vi: " + shape.tinhChuVi());
        shape.veHinh();
    }
}  
Nếu trong trường hợp này, bạn viết riêng 2 Class con ra thì tức là bạn sẽ phải viết từng void printInfo cho từng Class cụ thể. Đồng thời cùng phải tạo ra hai Array riêng để chứa từng loại ==> Quá dài dòng và phức tạp đúng không ?? Điều này rất bất tiện, mỗi khi có kiểu Shape mới bạn lại phải vào sửa, thêm phương thức trong Controller.java ==> Mất thời gian.
==> Chốt lại: Tính đa hình giúp cho các Class chỉ cần quan tâm đến đối tượng mình đang làm việc có thể làm được gì, chứ không quan tâm đó là cái gì :smile: Đây là một đặc điểm của OOP :wink:

4. Có thể khai báo <Lớp con> = new <Lớp cha> được không?

Câu trả lời là không được :) Vì khi khai báo <Lớp con> = new <Lớp cha> tức là bạn đang tạo một Object <Lớp con> và chứa nó trong <Lớp cha>. Lớp con sẽ nhiều thuộc tính/phương thức hơn so với lớp cha.Nếu khai báo dữ liệu kiểu con thì cần điền đủ dữ liệu cho nó, nhưng bạn lại new lớp cha, có dữ liệu ít (không đủ).
Vẫn có trường hợp lớp con chỉ kế thừa mà không thêm thắt gì cả. Nhưng để đảm bảo tính “mở rộng” thì <Lớp con> = new <Lớp cha> không được phép.

5. Upcasting và Downcasting là gì?

Đây là 2 cơ chế ép kiểu sử dụng phổ biến cho các loại biến tham chiếu.
1.Upcasting: Đây là cơ chế để bạn chuyển từ đối tượng Class con sang đối tượng là Class cha. Chú ý là lúc này đối tượng đó sẽ không dùng được các method của Class con nữa. Và nó cũng khác với việc khai báo <Lớp con> = new <Lớp cha>.
Cat cat = new Cat();
Animal animal2 = (Animal) cat; // Upcasting
2.Downcasting: Ngược lại thì đây là cơ chế để bạn chuyển từ đối tượng Class cha sang đối tượng là Class con. Chú ý là bạn chỉ có thể Downcasting các Object được khai báo kiểu <Lớp cha> = new <Lớp con> vì khi đó thì mới có thể chứa được Object mới. Cơ chế này thường được sử dụng khi bạn khai báo tính đa hình và muốn sử dụng các method, ... từ Class con.
Animal animal = new Cat();
Cat cat = (Cat) animal;

Cảm ơn các bạn đã đọc hết bài viết này :) Hy vọng các bạn ủng hộ và góp ý để mình viết các bài sau tốt hơn :)

2019-01-20

Tìm hiểu về domain name system

Tìm hiểu về domain name system

Tổng quan

DNS - Domain Name System hay hệ thống tên miền là một cơ sở dữ liệu phân tán nằm trên các server khác nhau lưu thông tin ánh xạ giữa domain name và địa chỉ IP. DNS thực hiện dịch domain name tới một địa chỉ IP và ngược lại.
Sau đây là sơ đồ hoạt động của DNS.

Một số khái niệm trong DNS

Domain name space

Là một cấu trúc dạng cây chứa toàn bộ không gian domain như hình ảnh sau đây:

Domain

Là một nhánh của domain name space. Sau đây ví dụ về domain "purdue.edu".

Domain name

Mỗi node trong cây có một nhãn. Một domain name của bất kỳ một node nào trong cây là thứ tự các nhãn trong đường dẫn từ node đó đến root, tên mỗi node được phân cách bằng dấu chấm .

Resource Record

Thông tin về domain name được lưu trong các resource record. Mỗi resource record đặc tả thông tin về một đối tượng cụ thể. DNS server sử dụng các record này để trả lời các DNS query. Dưới đây là một vài resource record phổ biến:
  • SOA - Start of authority: Record lưu thông tin quản trị zone và mỗi zone chỉ có duy nhất một SOA.
  • NS - Name server: Record lưu ánh xạ domain name tới một danh sách các name server.
  • A: Record lưu ánh xạ domain name tới một địa chỉ IP.
  • PTR - Reverse-lookup pointer: Record lưu ánh xạ địa chỉ IP tới một domain name.
  • MX - Mail exchange: Record lưu ánh xạ domain name tới một danh sách các mail server. Ví dụ khi bạn gửi mail tới contact@example.com thì mail sẽ được chuyển tới mail server được đặc tả trong MX Record.
  • CNAME: Record lưu ánh xạ một domain name tới một domain name khác.

Top level domain

Là domain ở cấp cao nhất ngay bên dưới root domain trong hệ thống phân cấp của DNS. Top level domain được chia ra làm 2 loại chính:
  1. Generic TLD (gTLD)
  2. Country Code TLD (ccTLD)
Ví dụ một vài gTLD:
  • .com: Cho các website thương mại
  • .org: Cho các tổ chức phi lợi nhuận
  • .edu: Giới hạn trong các trường học và tổ chức
  • .net: Ban đầu giới hạn trong các tổ chức hạ tầng mạng nhưng bây giờ thì không hạn chế
Ví dụ một vài ccTLD:
  • .us: United States
  • .in: India
  • .uk: United Kingdom
  • .vn: Vietnam
Hình ảnh cấu trúc cây DNS:

Delegation và Authority

Một trong những mục tiêu chính của thiết kế hệ thống DNS là phân cấp quản trị. Nó đạt được thông qua delegation - uỷ thác.
Cơ quan quản lý domain gọi là Authority. Cơ quan quản lý root domain và gTLD thuộc về ICANN - Internet Corporation for Assigned Names and Numbers. Tên miền ccTLD thì được quản lý bởi các quốc gia.
Một tổ chức quản lý domain có thể chia nó thành các sub-domain. Mỗi sub-domain có thể ủy quyền quản trị cho các tổ chức khác. Ví dụ domain "standford.edu" được uỷ quyền quản trị tới trường đại học Standard.

Name server và Zone

Name server: Là server lưu trữ các resource record về domain và thông tin name server của các sub-domain của nó. Các name server thường chỉ chứa thông tin đầy đủ về một phần của domain name space được gọi là zone.
Lưu ý: Root name server là name server của root domain hay name server gốc của toàn bộ hệ thống DNS.
Sau đây là ví dụ domain edu được chia thành các zone như: zone berkeley.edu, zone purdue.edu và zone nwu.edu zone. Và bản thân edu cũng là một zone.

DNS Resolver

Phía client của DNS gọi là DNS Resolver. DNS Resolver chịu trách nhiệm thực hiện các DNS query.

DNS Query

Có 3 loại DNS query:
  • Recursive query: Truy vấn đệ quy
  • Iterative query: Truy vấn lặp đi lặp lại
  • Inverse query: Truy vấn domain name cho địa chỉ IP chỉ định



Sau đây là các bước khi thực hiện phân giải tên miền chẳng hạn rutgers.edu.
  • Resolver sẽ gửi một query tới DNS local
  • DNS local sẽ tìm kiếm rutgers.edu trong cơ sở liệu của nó. Nếu có trả về địa chỉ IP cho Resolver. Nếu không thực hiện bước tiếp theo.
  • Resolver sẽ gửi query tới root name server
  • Root name server sẽ uỷ thác trả lời query đến name server của domain .edu
  • Name server của domain .edu tiếp tục uỷ thác trả lời query đến name server của domain rutgers.edu
  • Trả về thông tin IP được lấy từ A record cho Resolver.

Một vài mẹo khi sử dụng DNS

Cấu hình DNS local sử dụng hosts file

Tôi gặp một tình huống như sau: Khách hàng sẽ migration server sang một server mới mà không stop service trên server cũ + một số rule sercurity mà khách hàng config 2 server vs thông tin kiểu như sau:
  • Domain name example.com được gắn với IP của server A.
  • Cả server A và server B đều có cùng config server_name = example.com trên web server.
Vậy làm thế nào để access vào website example.com của server B?
Tôi thêm config sau vào file hosts với path là /etc/hosts ở các máy hệ linux hay mac.
SERVER-B_IP_ADDRESS example.com
Lưu ý: Host file được sử dụng giống như một resource record để phân giải domain name tới địa chỉ IP.
Khi đó nếu bạn gõ example.com lên browser nó sẽ chạy đến website example.com của server B thay vì server A. Để xác nhận xem config đã hoạt động ổn chưa bạn bật Develop Tools của browser rồi kiểm tra thông tin Headers của request có dạng như sau:
Request URL: http://example.com/
Request Method: GET
Status Code: 200 OK
Remote Address: SERVER_ADDRESS
Referrer Policy: no-referrer-when-downgrade

Cấu hình DNS cho domain name

Để một website hoạt động thì ta phải thực hiện thao tác trỏ domain name về website đó. Và có 2 cách để làm việc này đó là:
  • Trỏ thẳng domain name tới địa chỉ IP của server chứa website đó.
    hoặc
  • Thêm thông tin name server của nhà cung cấp server vào domain name.
Sau khi config xong bạn có thể sử dụng tool sau để kiểm tra thông tin cấu hình domain name:
https://ipinfo.info/html/ip_checker.php/

Sử dụng CNAME record

Giả sử bạn có 2 website là example.com và example.vn trên cùng một server. Khi đó bạn có thể config 2 domain name trỏ đến cùng một địa chỉ IP nhưng nếu bạn có ý định đổi địa chỉ IP của server thì bạn phải config IP lại cho cả 2 domain name trên.
Tuy nhiên nếu sử dụng CNAME record chẳng hạn trỏ domain name example.vn tới domain name example.com như ví dụ bên dưới thì khi đó bạn cần config IP lại chỉ ở domain main example.com mà thôi.
NAME               TYPE    VALUE
---------------------------------------
example.vn.        CNAME   example.com.
example.com.        A      192.0.2.23

Tài liệu tham khảo