Month: August 2018

  • Fully Shut Down Windows 10

    ทดสอบ Windows 10 รุ่น 1803 พบว่า หากเราจะให้เป็นการ shutdown ที่สมบูรณ์ ไม่ใช่การ shutdown แบบ hibernate แล้วละก็เราจะต้องเปิด command line แบบ Run as Administrator แล้วทำ 2 คำสั่งนี้

    powercfg.exe   /hibernate off
    shutdown  /s  /t  0

    การทำ shutdown ที่สมบูรณ์ เมื่อเราต้องการจะบูตด้วยแผ่นCD SystemRescueCd (หรือ USB boot เป็น Linux) แล้วต้องการจะใช้คำสั่ง ntfs-3g เพื่อ mount แบบ Read Write ได้สำเร็จ เช่น ntfs-3g  /dev/sda1  /mnt/custom เป็นต้น

    การทำ shutdown ที่ไม่สมบูรณ์ เมื่อใช้คำสั่ง ntfs-3g เพื่อ mount แบบ Read Write จะได้ข้อความแจ้งเตือนว่า ทำไม่ได้ และถูกบังคับให้เป็นการ mount แบบ Read-Only แทน
    Windows is hibernated. 

    References:
    How to disable and re-enable hibernation on a computer that is running Windows
    https://support.microsoft.com/en-us/help/920730/how-to-disable-and-re-enable-hibernation-on-a-computer-that-is-running

  • อย่าเชื่อเครื่องมือมากเกินไป …

    เมื่อเดือนมีนาคม 2561 ผมได้ทำการทดสอบเครื่องมือเจาะระบบ “N”  (ใช้ทดสอบว่าระบบเป้าหมายมีช่องโหว่ใดให้โจมตีบ้าง) ภายใต้ภาระกิจ “Honeypot” เพื่อทดสอบว่า เครื่องมือดังกล่าว สามารถรับรองความปลอดภัยของระบบปฏิบัติการของเครื่องเซิร์ฟเวอร์ ก่อนที่จะอนุญาตให้เข้าถึงได้จากอินเตอร์เน็ตได้หรือไม่

    *** การทดลองนี้อยู่ในสภาวะควบคุมที่รัดกุม เป็นระบบที่สร้างขึ้นมา แยกออกจากระบบอื่นที่อาจจะได้รับผลกระทบ และเป็นการทดลองเพื่อวัดความสามารถของเครื่องมือ ไม่ได้มุ่งโจมตีผู้ใด หรือระบบใด ***

    วิธีการทดสอบ

    จัดให้มีเครื่องทดสอบ ชื่อ honeypot.in.psu.ac.th อยู่บน VM และใช้เครื่องมือเจาะระบบ “N” ตรวจสอบ 2 ครั้ง โดยครั้งแรก (Baseline 01) เป็นการติดตั้งระบบปฏิบัติการ Ubuntu 16.04 LTS แบบ Default และ Update ให้เป็นปัจจุบันที่สุด แล้วรีบแจ้งให้ “N” ตรวจสอบ ครั้งที่ 2 (Baseline 02) ทำการติดตั้ง Web Server, PHP, MySQL และติดตั้งช่องโหว่อย่างง่ายที่พัฒนาขึ้นเอง (https://github.com/nagarindkx/honeypot) ลงไป โดยภาพรวมดังภาพที่ 1 แล้วรีบแจ้งให้ “N” ตรวจสอบ

    ภาพที่1: ภาพรวมของ Honeypot

    honeypot.in.psu.ac.th ประกอบด้วยโครงสร้างไฟล์ ดังภาพที่ 2

    ภาพที่ 2: โครงสร้างไฟล์ของ honeypot

    เมื่อคลิก Login with SQL Injection Vulnerable  จะได้ภาพที่ 3 ซึ่งจะส่งไปที่ไฟล์ badform.html โดยในฟอร์มนี้จะมีช่องโหว่ SQL Injection ทำให้สามารถเข้าเป็น admin ได้โดยลองใส่ username/password ดังนี้

    ภาพที่ 3: http://honeypot.in.psu.ac.th/badform.html

    ซึ่งจะได้ผลว่า สามารถเข้าเป็น admin ได้โดยไม่ต้องทราบรหัสผ่านที่แท้จริง แต่อาศัยการเขียน SQL Statement ที่ไม่รัดกุม และไม่ตรวจสอบ Input ก่อน ดังภาพที่ 4

    ภาพที่ 4: ช่องโหว่ SQL Injection

    เมื่อคลิก  Simple Non Persistent XSS   จะได้ภาพที่ 5  ซึ่งจะส่งไปยัง simple.php โดยจะเห็นได้ว่า สามารถใส่ชื่อ นามสกุล ลงไปใน URL ได้เลย ผ่านตัวแปร name  (ต้องลองใช้กับ FireFox ถ้าเป็น Google Chrome จะมี XSS Auditor ไม่ได้รับผลกระทบ)

    ภาพที่ 5: ช่องโหว่ Non Persistent XSS

     

    ช่องโหว่นี้ ทำให้ Hacker นำเว็บไซต์นี้ไป ดักเอา Cookie Session ของผู้อื่น หรือ Session HiJacking ดังภาพที่ 6
    ด้วย URL นี้
    http://honeypot.in.psu.ac.th/simple.php?name=%3Cscript%3Ealert(escape(document.cookie))%3C/script%3E

    ภาพที่ 6: Session HiJacking

    หรือ เปลี่ยนเปลี่ยน URL ที่ “Click to Download” ไห้ยังเว็บไซต์ที่ต้องการได้ เช่นเป็น hacked.com เป็นต้น ดังภาพที่ 7 ด้วย URL นี้
    http://honeypot.in.psu.ac.th/simple.php?name=%3Cscript%3Ewindow.onload=function()%20{%20var%20link=document.getElementsByTagName(%22a%22);%20link[0].href=%27http://hacked.com%27}%3C/script%3E

    ภาพที่ 7: HTML Injection

    เมื่อคลิก Login to Test Permanent XSS จะได้ภาพที่ 8  ซึ่งจะส่งไปยัง goodlogin.php

    ภาพที่ 8:ช่องโหว่ Persistent XSS

    ซึ่ง เป็น Form ที่ป้องกัน SQL Injection และ ไม่ยอมรับ username/password ว่าง หากไม่ทราบรหัสผ่านจริงๆ ก็จะเข้าไม่ได้ ดังภาพที่ 9

    ภาพที่ 9: กรณี Login ไม่สำเร็จ

    หาก Login เป็น user1 สำเร็จ จะสามารถเปลี่ยน Display Name ได้ ดังภาพที่ 10
    ทดลองด้วย

    username: user1
    password: user1123**

    ภาพที่ 10: user1 เมื่อ Login สำเร็จ สามารถเปลี่ยน Display Name ได้

    หาก user1 ต้องการดัก Session HiJack จาก Admin สามารถทำได้โดย แก้ Display Name ดังนี้

    <a href=”#” onclick=alert(escape(document.cookie))>User1</a>

    เมื่อกดปุ่ม Update จะได้ภาพที่ 11

    ภาพที่ 11: user1 วาง Session HiJacking สำเร็จ

    เมื่อ admin เข้ามาในระบบ ด้วย

    username: admin
    password: admin123**

    จะได้ภาพที่ 12

    ภาพที่ 12: admin จะมองเห็นรายชื่อ users ทั้งหมด ในที่จะเห็น user1 ที่มี display name ของตนเองเป็น Link

    เมื่อ admin ติดกับดัก ลองคลิก link ที่เขียนโดย user1 ก็จะเปิดเผย (และสามารถส่ง session กลับไปให้ user1 ได้หลายวิธี) ก็จะได้ผลดังภาพที่ 13

    ภาพที่ 13: แสดง Session ของ Admin ซึ่งในช่วงเวลานั้นๆ user1 สามารถเข้ามาเป็น admin ได้โดยไม่ต้องทราบรหัสผ่านของ admin

    *** และ มี Backdoor ที่อยู่ใน /uploads/ ไฟล์ image.php ที่ ไม่ได้แสดงใน index.php หน้าแรก ซึ่งจะสามารถส่งคำสั่งเข้าไปให้ Execute ได้ เช่น ls -l ดังภาพที่ 14 หรือ แม้แต่ wget ไฟล์จากภายนอกมาไว้ในนี้ได้ เพื่อสร้าง Backdoor ในที่ต่างๆ ซึ่งเรียกว่า Remote Code Execution

    ภาพที่ 14: Backdoor ใน /uploads/image.php ที่ไม่ได้อยู่ใน index.php หน้าแรกของ honeypot

    ผลการทดสอบ

    จากผลการทดสอบด้วย “N” เมื่อ Mon, 12 Mar 2018 13:57:16 ICT ผลดังภาพที่ 15

    ภาพที่ 15: แสดงรายการช่องโหว่ “N”  ตรวจพบ ประกอบด้วย 1 High, 5 Medium Risk

    ผลการทดสอบสามารถสรุปเป็นตารางได้ ดังตารางที่ 1

    ตารางที่ 1: แสดงผลเปรียบเทียบสิ่งที่ honeypot วางไว้ กับสิ่งที่ “N” ตรวจพบ ตามตำแหน่งไฟล์ต่างๆ

    ตำแหน่งไฟล์Honeypot วาง“N” ตรวจพบ
    badform.htmlSQL Injectionยอมรับได้
    – Web Application Potentially Vulnerable to Clickjacking (เป็น Form ที่ยอมให้เว็บอื่นเอาไปใส่ใน iframe ได้)
    login.phpJavaScript Injectionเป็น False Positive
    เพราะ Login Fail

    – CGI Generic SQL Injection (blind)
    – CGI Generic XSS (quick test)
    – CGI Generic Cookie Injection Scripting
    – CGI Generic XSS (comprehensive test)
    – CGI Generic HTML Injections (quick test)
    ยอมรับได้
    – Web Application Potentially Vulnerable to Clickjacking (เป็น Form ที่ยอมให้เว็บอื่นเอาไปใส่ใน iframe ได้)


    ไม่เข้าไปตรวจ JavaScript Injection เพราะไม่ได้ตรวจสอบ SQL Injection จากหน้า badform.html
    simple.phpNon-Persistent XSSยอมรับได้
    – CGI Generic XSS (quick test)
    – CGI Generic Cookie Injection Scripting
    – CGI Generic XSS (comprehensive test)
    – CGI Generic HTML Injections (quick test)
    goodlogin.phpเป็น False Positive เพราะ Login Fail
    – CGI Generic SQL Injection (blind)

    ยอมรับได้
    – Web Application Potentially Vulnerable to Clickjacking (เป็น Form ที่ยอมให้เว็บอื่นเอาไปใส่ใน iframe ได้)
    home.phpPersistent XSSไม่เข้าไปตรวจ เพราะไม่สามารถเดารหัสผ่านที่ถูกต้องได้
    /uploads/image.phpBackdoor (Remote Code Execution)ไม่เข้าไปตรวจ เพราะไม่มี Link จากหน้าแรก

    สรุปผลการทดสอบ

    1. น่าตกใจ ที่ “N” ไม่สามารถตรวจพบ SQL Injection ได้ในหน้า badform.html
    2. “N” ตรวจพบ XSS ในหลายรูปแบบในหน้า simple.php ซึ่งนับว่าดี
    3. “N” ตรวจสอบได้เฉพาะ URL ที่สามารถติดตามไปจากหน้าแรกได้เท่านั้น จะเห็นได้ว่า ไม่สาามารถเข้าไปตรวจสอบ home.php ซึ่งต้องเดารหัสผ่านให้ได้ก่อน และ /uploads/image.php ซึ่งไม่มีการเรียกจากหน้าแรก ซึ่งโดยทางปฏิบัติ Hacker เมื่อเจาะเข้ามาวางไฟล์ได้แล้ว จะเอา URL นั้นไปโพสต์ประกาศในกลุ่ม หรือ บนหน้าเว็บไซต์อื่นๆ เช่น zone-h.org เป็นต้น ทำให้ เราตรวจด้วย “N” ยังไงก็ไม่เจอ แต่ Google ตรวจเจอเพราะไปตรวจสอบเว็บไซต์ของกลุ่ม Hacker อีกที
    4. “N” ทำงานเป็นลำดับ ดังนั้น เมื่อ ไม่ตรวจพบ SQL Injection ในหน้า badform.html ก็ไม่ตรวจ JavaScript Injection ในหน้า login.php
    5. “N” เตือนเรื่องสามารถนำ Form ไปอยู่ใน iframe ของเว็บไซต์อื่นๆได้ ซึ่งนับว่าดี

    อภิปรายผลการทดสอบ

    การมีเครื่องมือในการเจาะระบบอย่าง “N” เป็นเรื่องดี ทำให้สามารถลดงานของผู้ดูแลระบบได้ อย่างน้อยก็เรื่องการตรวจสอบ Version ของ OS, Software ที่ใช้ ว่าได้รับผลกระทบต่อช่องโหว่ที่สำคัญ ซึ่งจะประกาศเป็นเลข CVE เอาไว้แล้ว ทำให้ตรวจสอบภาพรวมๆได้ และตรวจสอบได้ตาม Signature ที่บริษัทเค้ากำหนดมาเท่านั้น

    อย่างไรก็ตาม ในทางปฏบัติ “N” หรือ เครื่องมืออื่นๆที่ทำงานแบบ Outside-In อย่างนี้ จะไม่มีทางตรวจสอบ ช่องโหว่ ที่อยู่ “ภายใน” เครื่องได้ หากแต่ การตรวจสอบ Log File และ การตรวจสอบเครื่องเซิร์ฟเวอร์จากภายใน จึงเป็นสิ่งจำเป็นอย่างยิ่ง นอกจากจะทำให้เราตรวจพบช่องโหว่ต่างๆก่อนจะโดนรายงาน แล้ว ยังเป็น การสะสมความรู้ซึ่งสำคัญยิ่่งกว่า เพราะเราจะได้ทำการ ป้องกัน ก่อนที่จะต้องมาตามแก้ไข อย่างเช่นในปัจจุบัน

  • Kaggle – วิธีการใช้ K-Means บนข้อมูล iris

    ต่อจาก Kaggle – วิธีการใช้ Logistic Regression บนข้อมูล Iris ซึ่งเป็น Machine Learning แบบ Supervised Learning

    คราวนี้ ลองมาดูว่า ถ้า เราไม่รู้ว่า ข้อมูลแบบออกเป็นกี่กลุ่ม จะให้ Machine แบ่งกลุ่มได้อย่างไร หนึ่งในวิธีที่ได้รับความนิยมคือ K-Means Clustering

    มีคลิป ที่อยากให้ลองชม เพื่อความเข้าใจ StatQuest: K-Means Clustering

    เริ่มกันเลย

    1. นำเข้าข้อมูล และ Package ที่ต้องการ
    import pandas as pd
    import numpy as np
    from sklearn.cluster import KMeans
    iris = pd.read_csv('../input/mydata2/4-iris.data')
    data=iris.values
    X=data[:,[0,1]]
    Y = data[:,4]
    
    2. แสดงผลจากข้อมูล 2 มิติ ของ Sepal Length กับ Sepal Width จำแนกสีของจุดที่พลอตตาม Species
    import matplotlib.pyplot as plt
    # Truth
    label = set(iris['species'])
    for i in label:
    	species=iris[iris['species']==i]
    	plt.scatter(species['sepal_length'], species['sepal_width'])
    plt.show()
    
    ผลที่ได้
    3. จากนั้น ลองใช้ K-Means จำแนก Cluster สมมุติเราไม่รู้ว่ามีกี่ชนิด เริ่มต้นจาก 2 ก่อน
    from sklearn.cluster import KMeans
    kmeans = KMeans(n_clusters=2).fit_predict(X)
    kmeans
    ค่า kmeans จะได้ผลประมาณนี้ (คือ สิ่งที่ Machine จำแนกให้)
    4. นำข้อมูลมา Plot
    c=np.insert(X,2,kmeans, axis=1)
    import matplotlib.pyplot as plt
    # Kmeans Predict
    label = set(kmeans)
    for i in label:    
    	species=c[c[:,2]==i]
    	plt.scatter(species[:,0], species[:,1])
    plt.show()
    ผลที่ได้
    5. ลองปรับค่า n_cluster=3
    from sklearn.cluster import KMeans
    kmeans = KMeans(n_clusters=3).fit_predict(X)
    kmeans3
    ผลที่ได้
    5. ลองปรับค่า n_cluster=4
    from sklearn.cluster import KMeans
    kmeans = KMeans(n_clusters=4).fit_predict(X)
    kmeans3
    ผลที่ได้

    จะเห็นได้ว่า K-Means สามารถแบ่งกลุ่มของข้อมูลได้ โดยไม่ต้องอาศัย Label แต่ความถูกต้องอาจจะไม่มากนัก เหมาะสำหรับข้อมูลจำนวนมาก ๆ ที่ต้องการทราบว่า มีการกระจายตัวอย่างไรในเบื้องต้น

    ในเบื้องต้น ก็ขอให้ทราบถึง วิธีการใช้งานคร่าว ๆ ง่าย ๆ ก่อนครับ

  • Oracle Label Security

    Oracle Label Security (OLS) เป็นส่วนขยายของเทคโนโลยี Virtual Private Database (VPD) ซึ่งเริ่มนำมาใช้ตั้งแต่ Oracle 8i  OLS อนุญาตให้มีการควบคุมการเข้าถึงลงในแถวต่างๆ ตามป้ายกำกับที่ระบุ ฟังก์ชันการทำงานที่คล้ายคลึงกันสามารถทำซ้ำโดยใช้ Fine Grained Access Control (FGAC) แต่ OLS ให้โซลูชันที่ง่ายกว่าสำหรับการรักษาความปลอดภัยระดับแถว (row-level security) ในบทความนี้ฉันจะนำเสนอตัวอย่างง่ายๆของการกำหนดค่า OLS

    ตั้งค่าฐานข้อมูล

    • หากไม่ได้เลือกตัวเลือก Label Security เมื่อครั้งติดตั้ง Oracle Database สามารถเรียกตัวติดตั้งและเลือกตัวเลือก Label Security เพิ่มเติมได้ภายหลัง
    • เข้าระบบด้วยบัญชีผู้ใช้ Oracle เปิด terminal พิมพ์ dbca (Database Server เป็น Linux)
    • เมื่อได้ Welcome Screen คลิก Next
    • ที่หน้า Operation คลิก Configure Database Options แล้วคลิก Next
    • หน้า Database เลือกฐานข้อมูลที่ต้องการ คลิก Next
    • ที่หน้า Database Features คลิกเลือก Label Security คลิก Next
    • คลิก Finish
    • เมื่อจบการตั้งค่าให้ restart database

    สร้างผู้ใช้ทดสอบ

    คำสั่งทั้งหมดทำภายใน sqlplus สร้างผู้ใช้ ols_test มีรหัสผ่านว่า password โดยให้สิทธิ์ CONNECT, RESOURCE, SELECT_CATALOG_ROLE

    sqlplus, / as sysdba
    CONN / AS SYSDBA
    
    CREATE USER ols_test IDENTIFIED BY password 
    DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp
    GRANT CONNECT, RESOURCE, SELECT_CATALOG_ROLE TO ols_test;

    ต่อไปเป็นการให้สิทธิ์ในแพ็คเกจ OLS แก่ผู้ใช้ ols_test จำเป็นต้อง unlock ผู้ใช้ lbacsys และตั้งรหัสผ่านว่า lbacsys เพื่อใช้เป็นคนกำหนดสิทธิ์ต่างๆ ให้ ols_test ได้แก่สิทธิ์ execute บน sa_components, sa_user_admin, sa_label_admin, sa_policy_admin, sa_audit_admin, sa_sysdba, to_lbac_data_label และให้ ols_test เป็น lbac_dba

    sqlplus, / as sysdba, lbacsys/lbacsys
    ALTER USER lbacsys IDENTIFIED BY lbacsys ACCOUNT UNLOCK;
    
    CONN lbacsys/lbacsys
    
    GRANT EXECUTE ON sa_components TO ols_test WITH GRANT OPTION;
    GRANT EXECUTE ON sa_user_admin TO ols_test WITH GRANT OPTION;
    GRANT EXECUTE ON sa_user_admin TO ols_test WITH GRANT OPTION;
    GRANT EXECUTE ON sa_label_admin TO ols_test WITH GRANT OPTION;
    GRANT EXECUTE ON sa_policy_admin TO ols_test WITH GRANT OPTION;
    GRANT EXECUTE ON sa_audit_admin  TO ols_test WITH GRANT OPTION;
    
    GRANT LBAC_DBA TO ols_test;
    GRANT EXECUTE ON sa_sysdba TO ols_test;
    GRANT EXECUTE ON to_lbac_data_label TO ols_test;

    สร้าง Policy

    ต่อไปจะสร้าง policy ชื่อ region_policy ด้วยผู้ใช้ ols_test และระบุชื่อของ column ที่จะเป็นที่เก็บ label ว่า region_label

    sqlplus, ols_test/password
    CONN ols_test/password
    
    BEGIN
    	SA_SYSDBA.CREATE_POLICY(
    	policy_name => 'region_policy',
    	column_name => 'region_label');
    END;
    /
    
    GRANT region_policy_DBA TO ols_test;

    กำหนด component ของ label

    สร้าง component ของ label เพื่อใช้สำหรับ policy ที่สร้างไว้ตอนต้น region_policy
    – สร้างระดับไว้ 3 ระดับ คือ 20, 40 และ 60 มีชื่อเรียกสั้น ๆ ว่า L1, L2 และ L3 ชื่อเรียกยาว ๆ ว่า Level 1, Level 2 และ Level 3 ตามลำดับ
    – สร้างสิทธิ์การใช้งานไว้ 2 ชนิดประกอบด้วย 100, 120 มีชื่อเรียกอย่างย่อว่า M และ E และชื่อเรียกยาวว่า Manage และ Employee ตามลำดับ
    – สร้างกลุ่มของ policy ไว้ 4 กลุ่ม 20, 40, 60 และ 80 ชื่อย่อ R20, R40, R60 และ R80 ชื่อยาว Region North, Region South, Region East และ Region West ตามลำดับ
    สุดท้ายกำหนดให้ ols_test เป็นผู้มีสิทธิ์สูงสุดใน policy region_policy

    sqlplus, ols_test/password
    EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',20,'L1','Level 1');
    EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',40,'L2','Level 2');
    EXECUTE SA_COMPONENTS.CREATE_LEVEL('region_policy',60,'L3','Level 3');
    
    EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('region_policy',100,'M','MANAGEMENT');
    EXECUTE SA_COMPONENTS.CREATE_COMPARTMENT('region_policy',120,'E','EMPLOYEE');
    
    EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',20,'R20','REGION NORTH');
    EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',40,'R40','REGION SOUTH');
    EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',60,'R60','REGION EAST');
    EXECUTE SA_COMPONENTS.CREATE_GROUP('region_policy',80,'R80','REGION WEST');
    
    EXECUTE SA_USER_ADMIN.SET_USER_PRIVS('region_policy','ols_test','FULL,PROFILE_ACCESS');

    สร้าง Table ทดสอบ

    สร้าง table พร้อมข้อมูลทดสอบใน schema ols_test โดย table ชื่อ customers มีฟิลด์ id, cust_type, first_name, last_name, region, credit กำหนดให้ id เป็น Primary key และ insert ข้อมูลลง table ด้วย

    sqlplus, ols_test/password
    CONN ols_test/password
    
    CREATE TABLE customers (
    	id                  NUMBER(10) NOT NULL,
    	cust_type           VARCHAR2(10),
    	first_name          VARCHAR2(30),
    	last_name           VARCHAR2(30),
    	region              VARCHAR2(5),
    	credit              NUMBER(10,2),
    	CONSTRAINT customer_pk PRIMARY KEY (id));
    
    GRANT SELECT, INSERT, UPDATE, DELETE ON customers TO PUBLIC;
    
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 1, 'SILVER', 'Harry', 'Hill', 'NORTH', 11000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 2, 'SILVER', 'Vic', 'Reeves', 'NORTH', 2000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 3, 'SILVER', 'Bob', 'Mortimer', 'WEST', 500.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 4, 'SILVER', 'Paul', 'Whitehouse', 'SOUTH', 1000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 5, 'SILVER', 'Harry', 'Enfield', 'EAST', 20000.00);
    
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 6, 'GOLD', 'Jenifer', 'Lopez', 'WEST', 500.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 7, 'GOLD', 'Kylie', 'Minogue', 'NORTH', 1000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 8, 'GOLD', 'Maria', 'Carey', 'WEST', 1000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES ( 9, 'GOLD', 'Dani', 'Minogue', 'SOUTH', 20000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES (10, 'GOLD', 'Whitney', 'Houston', 'EAST', 500.00);
    
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES (11, 'PLATINUM', 'Robbie', 'Williams', 'SOUTH', 500.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES (12, 'PLATINUM', 'Thom', 'Yorke', 'NORTH', 2000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES (13, 'PLATINUM', 'Gareth', 'Gates', 'WEST', 10000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES (14, 'PLATINUM', 'Darius', 'Dinesh', 'EAST', 2000.00);
    INSERT INTO customers (id, cust_type, first_name, last_name, region, credit)
    VALUES (15, 'PLATINUM', 'Will', 'Young', 'EAST', 100.00);
    
    COMMIT;

    สร้าง label function

    เป็นการสร้าง function ชื่อ get_customer_label สำหรับสร้าง label ประกอบด้วย p_cust_type, p_region, p_credit
    – โดยกำหนด policy ระดับด้วย p_credit >2000 ก็จะมี v_label ว่า L3 ถ้า p_credit > 500 v_label คือ L2 และ p_credit < 500 v_label คือ L1
    – กำหนด p_cust_type เป็น platinum หรือไม่ถ้าเป็นก็จะอยู่ในจะมีิสิทธิ์ M ถ้าไม่ก็จะเป็น E โดยเอาค่าที่ได้มาต่อกับ v_label ข้อที่แล้ว
    – กำหนด p_region ถ้าเป็น north จะอยู่กลุ่ม R20 เป็นต้น และจะเอาค่าที่ได้ไปต่อกับ v_label ที่ได้จากข้อที่แล้ว
    – ค่าที่ return จา function นี้จะเป็นชื่อ policy และ v_label สุดท้ายที่ได้จากข้อกำหนดที่กล่าวมาข้างต้น

    sqlplus, ols_test/password
    CREATE OR REPLACE FUNCTION get_customer_label (
    	p_cust_type  IN  VARCHAR2,
    	p_region     IN  VARCHAR2,
    	p_credit     IN  NUMBER)
    RETURN LBACSYS.LBAC_LABEL AS
    	v_label  VARCHAR2(80);
    BEGIN
    	IF p_credit > 2000 THEN
    		v_label := 'L3:';
    	ELSIF p_credit > 500 THEN
    		v_label := 'L2:';
    	ELSE
    		v_label := 'L1:';
    	END IF;
    
    	IF p_cust_type = 'PLATINUM' THEN
    		v_label := v_label || 'M:';
    	ELSE
    		v_label := v_label || 'E:';
    	END IF;
    	IF p_region = 'NORTH' THEN
    		v_label := v_label || 'R20';
    	ELSIF p_region = 'SOUTH' THEN
    		v_label := v_label || 'R40';
    	ELSIF p_region = 'EAST' THEN
    		v_label := v_label || 'R60';
    	ELSIF p_region = 'WEST' THEN
    		v_label := v_label || 'R80';
    	END IF;
    
    	RETURN TO_LBAC_DATA_LABEL('region_policy',v_label);
    END get_customer_label;
    /
    
    SHOW ERRORS

    สั่งให้ Policy ทำงานกับ table ที่สร้าง

    เมื่อสั่งให้ Policy ทำงานจะเป็นการเพิ่ม column ที่เก็บ label ใน table เป้าหมาย

    sqlplus, ols_test/password
    CONN ols_test/password
    
    BEGIN
    	SA_POLICY_ADMIN.APPLY_TABLE_POLICY(
    	policy_name   => 'REGION_POLICY',
    	schema_name   => 'OLS_TEST',
    	table_name    => 'CUSTOMERS',
    	table_options => 'NO_CONTROL');
    END;
    /

    เริ่มสร้าง label

    เป็นการกำหนดค่าเริ่มต้นสำหรับ region_label ลงไปใน table ซึ่งถ้าไม่มีข้อมูลในฟิลด์นี้จะไม่มีใครสามารถเข้าถึงได้

    sqlplus, ols_test/password
    UPDATE customers
    SET region_label = CHAR_TO_LABEL('REGION_POLICY','L1');
    
    COMMIT;

    สั่งให้ Policy ทำงานอีกครั้ง

    ต่อไปจะเป็นการสั่งให้ policy ทำงานอีกครั้งใน table customers เพื่อเปลี่ยนค่าเป็นค่าที่ได้จะเป็นค่าจาก function ที่สร้างไว้

    sqlplus, ols_test/password
    BEGIN
    	SA_POLICY_ADMIN.REMOVE_TABLE_POLICY('REGION_POLICY','OLS_TEST','CUSTOMERS');
    	SA_POLICY_ADMIN.APPLY_TABLE_POLICY (
    	policy_name => 'REGION_POLICY',
    	schema_name => 'OLS_TEST',
    	table_name  => 'CUSTOMERS',
    	table_options => 'READ_CONTROL,WRITE_CONTROL,CHECK_CONTROL',
    	label_function => 'ols_test.get_customer_label(:new.cust_type,:new.region,:new.credit)',
    	predicate => NULL);
    END;
    /

    สั่งให้ label ทำงานกับข้อมูลในแต่ละแถว

    ปรับปรุงข้อมูลให้เป็นตามฟังก์ชันที่สร้างไว้กับข้อมูลแต่ละแถว

    sqlplus, ols_test/password
    UPDATE customers
    SET    first_name = first_name;
    
    COMMIT;

    สร้าง user ทดสอบ

    สร้าง user อื่นๆ เพื่อทดสอบ label ได้แก่ sales_manager, sales_north, sales_south, sales_east, sales_west
    – sales_manager มี label ว่า L3:M,E:R20,R40,R60,R80 แปลว่า sales_manager สามารถอ่านและเขียนข้อมูลได้ทุก Region
    – sales_north มี label ว่า L3:E:R20,R40 แปลว่า sales_north สามารถอ่านข้อมูลที่อยู่ใน Region North และ South
    – sales_south มี label ว่า L3:E:R20,R40,R60,R80 แปลว่า sales_south อ่านข้อมูลได้ทุก Region
    – sales_east มี label ว่า L3:E:R60 แปลว่า sales_east อ่านข้อมูล Region East ได้อย่างเดียว
    – sales_west มี label ว่า L3:E:R80 แปลว่า sales_west อ่านข้อมูล Region West ได้อย่างเดียว

    sqlplus, / as sysdba, (sales_manager, sales_nort, sales_south, sales_east, sales_west, ols_test)/password
    CONN / AS SYSDBA;
    
    CREATE USER sales_manager IDENTIFIED BY password;
    CREATE USER sales_north IDENTIFIED BY password;
    CREATE USER sales_south IDENTIFIED BY password;
    CREATE USER sales_east IDENTIFIED BY password;
    CREATE USER sales_west IDENTIFIED BY password;
    
    GRANT CONNECT TO sales_manager, sales_north, sales_south, sales_east, sales_west;
    
    CONN ols_test/password
    
    BEGIN
    	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_manager','L3:M,E:R20,R40,R60,R80');
    	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_north','L3:E:R20,R40');
    	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_south','L3:E:R20,R40,R60,R80');
    	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_east','L3:E:R60');
    	SA_USER_ADMIN.SET_USER_LABELS('region_policy','sales_west','L3:E:R80');
    END;
    /

    ทดสอบ Label Security 

    เข้าระบบผ่าน sqlplus ด้วย user ต่างๆ ที่สร้างในข้อที่แล้วเพื่อดูข้อมูลว่าถูกต้องหรือไม่ เพื่อความสะดวกจึงเข้าผ่านโปรแกรมสำเร็จรูปอื่นเพื่อให้ดูง่าย ได้ผลดังรูปต่อไปนี้นี้

    sqlplus, sales_manager, sales_north, sales_south, sales_east, sales_west

    จบขอให้สนุก

    ที่มา https://oracle-base.com/articles/9i/oracle-label-security-9i#Installation

  • WordPress new editor

    อีกไม่นาน WordPress เวอร์ชั่นถัดไป จะใช้ Editor ชื่อ Gutenberg เป็น default editor แทน โดยขยับให้ editor แบบเดิมไปเป็น plugin ชื่อ Classic editor ครับ

    วันนี้ก็ลองใช้ editor ใหม่นี้ และโพสต์เพจนี้ดูว่าใช้ยากมั้ย

    เมื่อ upgrade WordPress เป็น 4.9.8 ก็จะพบเพจเชิญชวน และ คำแนะนำ

    หน้าตา editor ก็ ประมาณนี้ 

    ตัวเลือกก็เป็น ปุ่มเปิด/ปิด ด้วยเครื่องหมาย สามเหลี่ยม เพื่อเปิดรายการมาให้เลือก เช่น categories ที่ต้องการ เมื่ออยู่ที่แท็บ document แต่ถ้า cursor วางอยู่ในข้อความ จะย้ายไปที่แท็บ Block จะเห็น ตัวเลือกอีกชุด

    น่าจะใช้งานได้ดีกว่าแบบเดิม

  • วิธีเอา Boxbe ออกไปจากชีวิตของคุณ

    Boxbe เป็น Free Service ที่พยายามจะจัดการกับ Spam โดยอยู่บนสมมุติฐานว่า ผู้ที่ไม่อยู่ใน Contact ของเรา หรือ อยู่ใน Guest List นั้น มีแนวโน้มจะเป็น Spam เมื่อมีการส่ง email จากกลุ่มนี้ ก็จะถูกเอาไปอยู่ในกล่องที่เป็น Wait List จึงทำให้กล่อง Inbox ซึ่งเราจะอ่าน email เป็นประจำนั้น มาจากคนที่อยู่ใน Contact เท่านั้น

     

    โดยความตั้งใจ ดูดี แต่ …

     

    คนใน Contact ของเรา เป็น Subset ของ email universe ที่เราจะต้องติดต่อด้วย สำหรับคนที่ไม่ได้ทำธุรกิจติดต่อกับคนที่ไม่เคยรู้จักมาก่อน หรือติดต่อเฉพาะคนในองค์กร ก็พอจะไปได้ แต่ในความเป็นจริง ไม่ใช่ทุกคนที่ต้องการอย่างนั้น

    อีกปัญหาหนึ่งคือ ก่อนหน้านี้ เมื่อมีคนที่ไม่ได้อยู่ใน Contact ของเราติดต่อมา สิ่งที่ Boxbe ทำคือ ส่ง email ตอบกลับไปยังผู้ส่ง ว่า “email ของคุณถูกส่งไปอยู่ใน Wait List” แล้วก็อธิบายด้วยข้อความที่ค่อนข้างสับสน

    จากนั้น ผู้ส่งที่ได้รับ email ตอบกลับมานั้น ก็อาจจะไม่เข้าใจ แล้วเหลือบไปเห็นปุ่ม “สีน้ำเงิน”  อะไรสักอย่าง แล้วคิดว่า ปุ่มนี้คือปุ่มที่ทำให้ email ของตน ส่งไปยังผู้รับได้ ก็เลยคลิก

     

    เมื่อคลิก สิ่งที่เกิดขึ้นคือ Boxbe จะพาไปยังหน้า Sign-Up Boxbe (จริง ๆ แล้ว ปุ่มสีน้ำเงิน นั่นก็บอกแล้วว่า เป็นการ Sign-Up) แล้วก็ของ Permission ในการ “Read, send, delete and manage your email”

    และแน่นอน ผู้ใช้ก็กด Allow เป็นธรรมดา หลังจากนั้น …. คุณก็เป็นสมาชิกของ Boxbe ไปโดยไม่รู้ตัว และเกิดปฏิกิริยาลูกโซ่ตามมา คือ คนที่ส่ง email ถึงคุณก็จะได้รับข้อความตอบกลับจาก Boxbe และ คนเหล่านั้นก็ทำอาการเดียวกับคุณ 5555 เข้าใจตรงกันนะ

     

    เอาเป็นว่า มาดูวิธีเอา Boxbe ออกจากชีวิตดีกว่า

    1. อันดับแรก ให้ไป Delete Boxbe Account ก่อน โดยไปที่ https://www.boxbe.com/ แล้วคลิกที่ Sign In หรือ ถ้า Login ค้างอยู่ให้คลิกที่ Dashboard
    2. จากนั้น คลิก Disable Account
    3. แล้วพิมพ์คำว่า Yes แล้วคลิกปุ่ม Close Forever

    ยัง …. ไม่ยังไม่ตาย เพราะตอนที่ Sign Up นั้น เราไปอนุญาตให้ Boxbe เชื่อมต่อกับ Account ของเรา ในตัวอย่างนี้ เป็นกรณีของ Gmail

    1. ไปที่ https://myaccount.google.com/permissions เราจะเจอ Boxbe นั่งยิ้มหวานอยู่
    2.  บรรจงคลิก Boxbe แล้วคลิก Revoke Access
    3. แล้วก็คลิก OK

     

    จบจ้า