วันพฤหัสบดีที่ 3 มกราคม พ.ศ. 2562

ทดสอบ : Select Topic Web Service, midterm

นาย สุเมธ บุญญา 58-010126-3018-1


1. ดึงข้อมูล About me(profile) จาก Web Service

  • ข้อมูลนักศึกษา
    • รหัสประจำตัว
    • ชื่อ - นามสกุล
    • งานอดิเรก

  • สร้าง server เพื่อรอการ request จาก client


  • สร้าง client request


  • ผลลัพธ์



2 ทำ Web Service สำหรับบริษัทส่งของ

  • สร้าง Database เก็บข้อมูล
    • ID, Sender, Receiver, Weight, Status
  • รับการ insert ข้อมูล จาก client 
  • client ส่งค่า ID, Sender, Receiver, Weight  ส่วน status server จะเป็นฝ่ายจัดการ


  • ผลลัพธ์


จะสังเกตได้ว่ามี Item ที่ 5 ID 20001 เพิ่มเข้ามา

2.1 เขียน function อัพเดตข้อมูล status

  • ฟังก์ชันอัพเดต Item ที่ server
  • ส่งค่าจาก client 

  • ผลลัพธ์




จะสังเกตได้ว่ามี Item ที่ 2 ID 10003 status เปลี่ยนจาก 0 เป็น 1


2.2 เรียกข้อมูลทั้งหมดออกมาแสดง

  • ฟังก์ชันแสดง ที่ server
  • request จาก client 
  • ผลลัพธ์





---------------------------------------------------------------------------------------------------------
Reference :



วันเสาร์ที่ 1 ธันวาคม พ.ศ. 2561

Web Service Performance : Load Test

ใช้ SOAP UI เพื่อทดลอง load test เพื่อหา Transaction per second ของ WebService ของเรา
โดยทำตามขั้นตอนดังนี้

ทำการสร้าง SOAP Project โดยติ๊ก Create a Testsuite for the imported WSDL

 เมื่อติ๊กจะมีให้เลือก ว่าจะสร้าง Test สำหรับ Operation ใดบ้าง ให้ติ๊กด้านล่าง (Generate a default LoadTest)

จากนั้นจะได้รายการมาทางด้านซ้ายของโปรแกรม
ให้เลือก Operation ที่ต้องการจะ Load Test จากนั้นเลือก TestSuites แล้วเลือก LoadTest 
ตั้งค่า Thread ( จำนวนเครื่องที่จะ Requset ไป ) , Limit (เวลาที่ใช้) ได้ทางด้านขวา เมื่อตั้งค่าเสร็จกดปุ่ม Run (สามเหลี่ยมสีเขียวๆ)
จะได้ผลลัพธ์อยู่ภายในช่องที่ 3 

ทดลองกับ Web service

 จะเห็นว่า online (heroku) จะได้ response time ที่สูงกว่า เนื่องจากระยะทางระหว่างเครื่องเราและ Server

จะเห็นว่า tps (transaction per second) ของ heroku จะเยอะกว่าบนเครื่อง

ผล test ของ heroku

ผล test ของเครื่อง

SOAP Authentication Ruby (washout gem)

ทดลองใช้ Authentication หรือการยืนยันตนเพื่อใช้งาน WebService ด้วย washout gem ของ Ruby on rails


ทำการเพิ่ม
soap_service namespace: "wash_out", wsse_username: "username", wsse_password: "password"
จากเดิมเป็น
soap_service namespace: 'urn:WashOut'

ภายใน airwebservice_controller.rb ที่อยู่ ใน controller

จากนั้นเวลาจะใช้ WebService จะต้องส่ง username และ password ที่ตั้งไว้ด้านบน (ตัวหนา) เพื่อใช้งาน

ตัวอย่างการส่ง Request ด้วย SOAP UI
กรณีส่งไม่มี Header

ส่ง Username และ Password ใน Header ไปด้วย
ตัวอย่างโค้ด Python สำหรับใส่ Header

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import zeep
from zeep import Client
import time

client = Client(wsdl='http://localhost:3000/airwebservice/wsdl')
header = zeep.xsd.Element(
            'Security',
            zeep.xsd.ComplexType([
                zeep.xsd.Element(
                    'UsernameToken',
                    zeep.xsd.ComplexType([
                        zeep.xsd.Element('Username',zeep.xsd.String()),
                        zeep.xsd.Element('Password',zeep.xsd.String()),
                    ])
                ),
            ])
        )
# https://stackoverflow.com/questions/42963114/python-zeep-soap-complex-header
header_value = header(UsernameToken={'Username':'username','Password':'password'})
result = client.service.get_all_airinfo(_soapheaders=[header_value])
print(result)
ผลลัพธ์ที่ได้

ความปลอดภัยที่ลองนำไปใช้กับ soap service


------------------------------------------------------------

การใช้งาน public , private key

link git lab ในส่วน controller
https://gitlab.com/sovernut/select_webservice/blob/master/app/controllers/airwebservice_controller.rb

ทำการเปลี่ยนข้อมูลที่จะส่งให้อยู่ในรูป ข้อความ แทน xml



โดย โค้ดที่เกี่ยวของมีดังนี้

ฝั่ง server

ส่วนเข้า รหัส

   def encrypt_asym(text)
        file = File.join(Rails.root, 'app', 'keys', 'public_key2.pem')
        public_key = OpenSSL::PKey::RSA.new(File.read(file))
        encrypt = Base64.encode64(public_key.public_encrypt(text))
        return encrypt
    end

จะทำการ ใช้ public key ของฝั่ง client ที่มี ทำการเข้ารหัสข้อความและ คืนค่า ที่เข้ารหัสแล้ว

ส่วนที่เป็น service


    soap_action "get_all_airinfo",
        :args   => nil,
        :return =>  [ AirInfomationWithEncrypt ]
    def get_all_airinfo
        @posts = Airinfo.all
        array_of_post = []
        @posts.each do |post|
            hsh = {}
            hsh["no"] = post.no
            hsh["date"] = post.date_t.iso8601(0)
            hsh["temp"] = post.temperature
            hsh["humid"] = post.humid
            array_of_post.push(hsh)
        end
        builder = Nokogiri::XML::Builder.new do |xml|
            xml.root do                           # Wrap everything in one element.
              process_array('airinformation',array_of_post,xml)  
            end
          end
        string = builder.to_xml 
        new_hash = { :iv => "ok" , :data => encrypt_asym(string)}
        render :soap =>  [ :airinfomationEncrypt => new_hash ]
    end
 โดยเนื้อหาหลักๆ จะอยู่ตรงสีแดง ที่ทำการแปลง xml เป็นก้อน string และทำการเข้า ขั้นตอน

เข้ารหัส และส่งกลับไปใน soap service นั่นเอง ในส่วนของ :return [ airInformationWithEncrypt ] นั้น

จะเชื่อมโยงกับ โมเดลข้อมูลดังนี้

class AirInfomationWithEncrypt < WashOut::Type
    map :airinfomationEncrypt => { :iv => :string , :data => :string}
end
ซึ่งจะมีการตรวจสอบความถูกต้องอัตโนมัติ

ทางฝั่ง client นั้นจะทำการ ถอดรหัสดังนี้

require 'savon'
require 'pp'
require 'openssl'
require 'base64' 
client = Savon::Client.new(wsdl: "http://airwebservice.herokuapp.com/airwebservice/wsdl")
result2 = client.call(:get_all_airinfo)
private_key = OpenSSL::PKey::RSA.new(File.read('private_key.pem'))
encrypt = result2["data"]
decrypt = private_key.private_decrypt encrypt
โดยใช้ private key ที่มี ถอดรหัสออกมา โดย encrypt คือตัวแปรที่เก็บข้อความที่เข้ารหัส

ที่ได้จาก ตัว service

**** การสร้างกุญแจ ****

ซึ่งหากใช้งานกุญแจ ที่มีความยาวไม่เพียงพอต่อข้อมูล แล้วละก็ จะทำให้ เกิด error ความยาวคีย์ได้

ซึ่ง เราจะใช้งาน key ที่ขนาด 16384 จากเดิมที่มี 2048 ทีมี error




ไปเป็น




 ผล จากการนำข้อมูลที่เข้ารหัสไว้มาถอด



รูปข้อมูลที่เข้ารหัสแล้ว



"<?xml version=\"1.0\"?>\n<root>\n  <airinformation>\n <no>1</no>\n  <date>2018-10-21T07:47:00Z</date>\n <temp>30.0</temp>\n    <humid>60.0</humid>\n </airinformation>\n <airinformation>\n    <no>2</no>\n
<date>2018-10-21T07:49:00Z</date>\n    <temp>28.0</temp>\n <humid>62.0</humid>\n  </airinformation>\n <airinformation>\n <no>3</no>\n    <date>2018-10-20T22:55:55Z</date>\n <temp>25.0</temp>\n   <humid>55.0</humid>\n </airinformation>\n <airinformation>\n    ….

ข้อมูลที่ถูกถอดออกมา มีความถูกต้องใช้งานได้จริง


เรื่องความปลอดภัยทีได้ไปลองมา

1 ลองแบบ 
PBKDF2 Password-based Encryption

ทางฝั่ง เข้ารหัส

message = "<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>"
cipher = OpenSSL::Cipher.new 'AES-128-CBC'
cipher.encrypt
iv = cipher.random_iv
pwd = 'admin123456'
salt = OpenSSL::Random.random_bytes 16
iter = 20000
key_len = cipher.key_len
digest = OpenSSL::Digest::SHA256.new
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
cipher.key = key
encrypted = cipher.update message
encrypted << cipher.final

ทางฝั่ง ถอดรหัส

cipher = OpenSSL::Cipher.new 'AES-128-CBC'
cipher.decrypt
cipher.iv = iv # the one generated with #random_iv
pwd = 'admin123456'
salt = ??
iter = 20000
key_len = cipher.key_len
digest = OpenSSL::Digest::SHA256.new
key = OpenSSL::PKCS5.pbkdf2_hmac(pwd, salt, iter, key_len, digest)
cipher.key = key
decrypted = cipher.update encrypted
decrypted << cipher.final

โดย จะต้องใช้กุญแจ ตัวเดียวกัน คือมี password ที่เหมือนกัน iterator เหมือนกัน salt เหมือนกัน

หรือก็คือ เป็น กุญแจแบบสมมาตร

ผลลัพธ์จากการถอดรหัสและเข้ารหัส



สามารถถอดได้ตามปกติ

-----------------------------------------------------

2 ลองแบบ กุญแจไม่สมมาตร มี กุญแจสาธารณะ และ กุญแจส่วนตัว

โดยอยู่บนเครื่องเดียวกัน

เริ่มจากการสร้าง กุญแจ มา 1 คู่ก่อน แล้วเก็บใน text .pem

require 'openssl'
key = OpenSSL::PKey::RSA.new 2048
open 'private_key.pem', 'w' do |io| io.write key.to_pem end
open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end

จะได้ไฟล์มาดังนี้


จากนั้นทางฝั่ง ผู้ส่ง ที่จำลองขึ้นมาจะมีโค้ดดังนี้

public_key = OpenSSL::PKey::RSA.new(File.read('public_key.pem'))
message = "<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>"
encrypt = public_key.public_encrypt message
p encrypt
open 'encrypt.txt', 'w' do |l| l.write encrypt end

โดยจะดึงกุญแจสาธารณะ มาใช้ในการเข้ารหัสข้อความ แล้วเก็บใน text เสมือน ส่งออกไป


ข้อความประมาณนี้


���:�+�ID�(�*��%"j;D4�>}�11N�j�Zz��d�t.�/���J|��4�l�Q�Yg�6
sO)�R�WA�Wt�){�X-W��.�V���q7T�s\�Vxk�l��q�]�[�pV,��� �W%��2kz��HJ���������b=�T�t:���L�\��O�hj��"�����9d_����"-
�*B2�j:ϩ�]�*- �%�\� �#���]�
D�F����^)�˻����
�xo�


จากนั้น ทำการให้ฝั่งผู้รับ ถอดรหัสโดยใช้โค้ดดังนี้

private_key = OpenSSL::PKey::RSA.new(File.read('private_key.pem'))
encrypt = File.read('encrypt.txt')
decrypt = private_key.private_decrypt encrypt
ดึงข้อความจากไฟล์มาเสมือนได้รับแล้ว ใช้กุญแจส่วนตัวที่เป็นคู่กันกับที่ส่งมา ถอดรหัส

จะได้ข้อความที่ถูกต้อง

** กุญแจจะมีลักษณะประมาณนี้



----------------------------------------------------------------------------------------------------------------

3 ต่อมาเรื่อง signature

ใช้ private key เข้ารหัส แล้วใช้ public key ถอดออกมาเพื่อยืนยันว่า ถูกส่งมาจากเจ้าของจริงๆ
เนื่องจากถ้าใช้ key ที่ไม่ใช่คู่กันจะถอดไม่ได้

http://ruby-doc.org/stdlib-2.5.3/libdoc/openssl/rdoc/OpenSSL.html

โค้ดฝั่งผู้ส่ง


private_key = OpenSSL::PKey::RSA.new(File.read('private_key.pem'))
message = "<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>"
digest = OpenSSL::Digest::SHA256.new
signature = private_key.sign digest, message
open 'signature.txt', 'w' do |l| l.write signature end
สร้างไฟล์ signature ที่ถูกเข้ารหัสข้อความด้วย private key เสมือนส่งออกไป




แล้วทางฝั่งรับ ก็อ่านไฟล์ แล้วแก้ออกมาเช็คว่าตรงกับข้อความเดิมมั้ย

public_key = OpenSSL::PKey::RSA.new(File.read('public_key.pem'))
digest = OpenSSL::Digest::SHA256.new
signature = File.read('signature.txt')

if public_key.verify digest, signature, message
puts 'Valid'
else
puts 'Invalid'
end

ได้ผลลัพธ์คือ ถูกต้อง



ซึ่งถือว่า เช็คได้ว่าถูกส่งมาจาก key คู่เดียวกันจริงๆ

----------------------------------------------------------------------------------
 

จดโดเมน และ ใช้งาน certificate:ssl [ https ]

เริ่มจากการ หาผู้ให้บริการจดโดเมนก่อน ซึ่ง เลือก https://th.godaddy.com/


จากนั้น ทำการค้นหาโดเมน ที่ต้องการ โดยพิมในช่องค้นหาเพื่อเช็คว่ามีคนใช้ไปแล้วหรือไม่


ในที่นี้ใช้ lightyourside.xyz จากนั้นทำการสมัครสมาชิค และกดเพิ่มไปในตระกร้าสินค้า

ซึ่งรายละเอียดปลีกย่อย นั้นต้องอ่านเอาเอง แต่มีส่วนที่น่าสนใจคือสามารถตั้งค่า ความเป็นส่วนตัว
ของการแสดงข้อมูลเจ้าของได้

จากนั้น จะเห็นได้ว่า ทางเว็ป นั้นได้ เพิ่มเงื่อนไขต่างๆ เช่น ต่ออายุอัตโนมัติ รวมทั้งจ่ายเงินล่วงหน้าอยู่
เราจึงต้องเอาออกเองตามความต้องการ


ซึ่งขั้นตอนการซื้อ ก็มีเพียงเท่านี้ หลังจากนี้ หากต้องการตั้งค่านำไปใช้งานมีได้หลายวิธี

วิธีแรก แบบ redirec ไปเลย ก็ทำตามขั้นตอนในรูปได้


คลิกที่ เชื่อมต่อโดเมนกับไซต์ที่มีอยู่แล้ว ขวามือล่าง

และทำการเพิ่ม ลิงค์ ในช่องส่งต่อไปยังไซต์ใดๆ
ซึ่งจะได้ผลลัพธ์ดังนี้
เข้าไปที่ 

lightyoursides.xyz จะทำการ redirec ไปที่

http://airwebservice.herokuapp.com/airwebservice/wsdl

** เพิ่ม  http://airwebservice.herokuapp.com/airwebservice/wsdl ในช่อง นั้น








หรือจะใช้วิธีแบบ
กำหนด cname 



โดยการคลิก ปุ่ม DNS ด้านบนแล้วเลือกจัดการ



โดยเปลี่ยนการตั้งค่าในช่อง cname , name = www , value = link โดยไม่มี www. นำหน้า และ ไม่มี
uri 

จะได้ผลลัพธ์เช่นเดิมแต่ต้องพิม www.lightyourside.xyz ซึ่งต่างจากเดิมที่แค่พิม lightyourside.xyz

------------------------------------------------------------------------------------------------------------------------

ต่อมา จะทำการใช้งาน ssl certificate ซึ่ง เราต้องการตัวที่ใช้งานได้ฟรี แต่เนื่องจาก ปกติแล้ว จะต้อง
เสียเงินให้กับ heroku เพื่อเปิดใช้งาน ssl ดังนั้น เราจึงหาตัวช่วยเพิ่ม โดยใช้งานบริการของ
cloundflare ซึ่งมีบริการที่หลากหลาย ซึ่งการให้บริการ DNS , CDN, SSL ก็เป็นหนึ่งในนั้น
ข้อมูลเพิ่มเติม
https://www.cloudflare.com/



รูปแบบที่เราจะทำการใช้งาน

ซึ่งในการใช้งานนั้นที่เว็ป cloundflare จะมีบอกอยู่แล้ว

สมัครและทำการ เพิ่ม ไซต์ในช่องได้เลย



กดไปเรื่อยๆตามการตั้งค่าต่างๆที่ต้องการ [ พวกเสียเงินและฟรี ]

จนมาถึงหน้า 

ที่เขาจะให้เราไปทำการเปลี่ยน  nameservers ที่อยู่ใน ผู้ให้บริการ โดเมนเก่าของเราซึ่งของเราเป็น

 GoDaddy

ซึ่งเขาจะมี วิธีการเปลี่ยนให้ด้วย

ไปที่ GoDaddy  และคลิกที่ โดเมนของเรา

จากนั้นทำการเปลี่ยน nameserver





*nameserver จะเป็นตัวที่บอกว่า เมื่อเข้าโดเมนแล้ว จะให้วิ่งไปที่โฮสติ้งที่ไหน

เราทำการเปลี่ยนให้เมื่อเข้าโดเมนแล้วจะวิ่งไปที่ cloundflare แทนที่จะเป็น GoDaddy ซึ่ง

หลังจากนี้การตั้งค่าต่างๆ ต้องมาทำที่ CloundFlare แล้ว



รอสักครู่ จนกระทั้งสถาณะเป็น



Active

จากนั้นไปเช็คที่เว็ปเรา



จะเห็นได้ว่าได้ใบ certificate , ssl มาแล้ว

ซึ่ง หากต้องการ certificate ที่ดีกว่าสามารถจ่ายเงินได้



เป็นอันจบ เรื่องของการจดโดเมนและใช้งาน certificate