plus emotion magic to the knowledge of logic.


เขียน app ใน IPhone อยู่ๆก็ล่มตลอด ดูใน log สาเหตุคือ มีการพยามเอาค่า null เข้าไปใน property ที่รับค่า string ทั้งๆที่ object ตัวนั้นไม่น่าจะมีค่า null ได้ จะให้ตรวจค่าว่าเป็น NSNull Null แล้วไม่ต้องใช้มัน? เหมือนที่ใน forum ios บอกก็ไม่ไหวทำข้อมูลหายไปเฉยๆเลย

ลองตรวจข้อมูลที่มาจาก PHP ดูใน array print_r มาดูแล้วรายการนั้นก็เป็น string ปกติ แล้ว null มาจากไหน? เปิดไฟล์ json ดูอีกที ค่าเป็น null จริงๆ แปลว่า json_encode แปลงให้ผิด งงกว่าเดิมอีก มันไม่เคยเพี้ยนเลยนี่น่า ลองใช้ trim , htmlspecialchars ดูก็ไม่ช่วยอะไร

หาดูใน stackoverflow.com เจอเต็มๆ http://stackoverflow.com/questions/1972006/json-encode-is-returning-null เกิดจาก query จาก database แล้วส่งชุดตัวอักษรกลับมาอีกแบบ แก้ได้โดยใช้คิวรี่ SET CHARACTER SET utf8; ก่อน ลองเพิ่มคิวรี่ดู เรียบร้อยทำงานได้ตามปกติ ^_^ ซะที

ใช้ server คนละตัวนี้ต้องตรวจอะไรเยอะเหมือนกัน


Code สั้นๆ ไว้แสดง message เวลา javascript มี error หรือจะดัดแปลงให้ส่ง error กลับไปที่ server ผ่าน ajax ก็ได้ครับ

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>javascript onerror</title>
</head>

<body>
<script>
window.onerror = function (msg, url, line) {
	str = "Message :\t\t"+msg+"\nUrl :\t\t\t"+url+"\nLine number :\t"+line;
	alert(str);
}

/* ตัวอย่างไปเรียก function ที่ไม่มีจริง */
noBody();
</script>
</body>
</html>

เรื่องที่เกี่ยวข้อง


ข้อเสียอย่างหนึ่งเวลาใช้ Ajax คือ เวลามี error อะไร user จะไม่ทราบอะไรเลย เพราะว่าเป็นการโหลดแบบเบื้องหลัง บางทีโหลดเกือบจะเสร็จแล้ว แต่เห็นหน้านิ่งๆ เลย refresh ใหม่ซะเลย ความจริง jQuery มี event onErrors ไว้สำหรับจัดการเวลาใช้ Ajax แล้วมีปัญหาอยู่แล้ว แต่การที่จะต้องมาเขียนกำหนดให้ทุกตัวที่เรียกใช้ Ajax ก็ไม่สดวกเลย จึงมี $.ajaxSetup ไว้ให้สามารถกำหนดคุณสมบัติที่เป็นส่วนกลางให้คำสั่ง Ajax ต่างๆ ทั้ง $.Ajax, $.get, $.json, $.post ใช้ร่วมกัน แค่ประกาศใช้ $.ajaxSetup เอาไว้ล่วงหน้า

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery.ajaxSetup</title>
</head>

<body>
<script src="assets/jQuery/jquery.min.js"></script> 
<script>
$.ajaxSetup({
	"cache": false,
	"error": function(jqXHR, exception)
	{
		if(jqXHR.status === 0)
		{
			alert('Not connect.\n Verify Network.');
		}
		else if(jqXHR.status == 404)
		{
			alert('Requested page not found. [404]');
		}
		else if(jqXHR.status == 500)
		{
			alert('Internal Server Error [500].');
		}
		else if(exception === 'parsererror')
		{
			alert('Requested JSON parse failed.');
		}
		else if(exception === 'timeout')
		{
			alert('Time out error.');
		}
		else if(exception === 'abort')
		{
			alert('Ajax request aborted.');
		}
		else
		{
			alert('Uncaught Error.\n' + jqXHR.responseText);
		}
	},
	"scriptCharset": "utf-8",
	"timeout": 60000
});

$.post('nofile.php', function(data){
	alert(data);
});
</script>
</body>
</html>

เรื่องที่เกี่ยวข้อง


การเก็บรหัสผ่านในระบบ ไม่ควรเก็บรหัสผ่านไว้ตรงๆ ถ้า user ใช้รหัสผ่าน 1234 ก็ไม่ควรบันทึกข้อมูล 1234 ลงไป มี 2 เหตุผลคือ

  1. ถ้าโดนขโมยข้อมูลในฐานข้อมูลไป hacker cracker จะรู้ทั้งหมดว่าใครใช้รหัสผ่านอะไร แต่เราอาจจะไม่รู้ว่าโดนเล่นไปแล้ว จนมีความเสียหายออกมา (sony, apple, microsoft, กระทรวงกลาโหมสหรัฐโดนมาหมดแล้ว ถึงจะเป็นเว็บเล็กๆ ก็ไม่มีเหตุผลอะไรที่จะคิดว่า ถ้า hacker จะทำจริงๆ แล้วเว็บเราจะปลอดภัย)
  2. ถ้ามีการทำงานอะไรผิดพลาดขึ้นมาก็จะไม่มีใครพูดว่า ฉันไม่ได้ทำ ฝ่าย it นั่นละทำรึเปล่า ก็รู้รหัสผ่านของทุกคนไม่ใช่เหรอ (เคยเจอปัดความรับผิดชอบง่ายๆ แบบนี้จริงๆ ตอนนั้นโชคดีที่มี ip log ช่วยไว้)

ใน PHP จะนิยมใช้ md5 เข้ารหัสแปลง password เป็นตัวอักษร 32 ตัวอักษรที่อ่านยังไงก็ดูไม่ออกว่าต้นฉบับคืออะไร แต่เพราะว่ามันเป็นวิธีที่ถ้าป้อนรหัสผ่านเดียวกันลงไป ก็จะได้คำตอบเหมือนเดิมทุกครั้ง ไม่ว่าจะทำในเครื่องไหน ทำให้เวลามีคนขโมยข้อมูลในตารางสมาชิกออกไปได้ จะสามารถหารหัสผ่านจริงๆ ได้ถ้าเอาไปเที่ยบกับตาราง rainbow table (ตารางที่เกิดจากการเปลี่ยนตัวอักษรไปเรื่อยๆ จากนั้นแล้วเข้ารหัสแล้วเก็บเอาไว้เปรียบเทียบหารหัสผ่านต้นฉบับ) หรือจะใช้บริการเว็บอย่าง md5decrypter, md5this ทำให้ยังไม่ปลอดภัยเท่าที่ควร

วิธีแก้คือใช้ salting ? ตอนเจอวีธีนี้ครั้งแรก งงว่ามันเกี่ยวอะไรกับเกลือ, การใส่เกลือ salting คือการเพิ่มชุดของสตริงเข้าไปในรหัสผ่านก่อนเข้ารหัส ตามตัวอย่าง

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>md5 salting</title>
</head>
<body>
<?php
$password = '1234';
echo '<br>password = "',$password,'"<br>MD5 ได้ <b>',md5($password),'</b><br>';
$salt = '2MnLPPdUZDHBQMYz5rB3GhMJYQRV9MyaYA3QHXEz';
echo '<br>password = "',$password,'" salt="',$salt,'"<br>MD5 ได้ <b>',md5($password.$salt),'</b><br>';
$salt = 'JnwMeUTJgMfjjM5E28jyHqQZ2JLRUnZk3FnM9zUK';
echo '<br>password = "',$password,'" salt="',$salt,'"<br>MD5 ได้ <b>',md5($password.$salt),'</b><br>',
'<br>ทดลอง decode <a href="http://www.md5decrypter.co.uk" target="_blank">md5decrypter</a>';
?>
</body>
</html>

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

ตัวอย่างระบบที่ใช้วิธีนี้คือ prestashop สมุติว่าลืมรหัสผ่านผู้ดูแลระบบเรานอกจากขอรับรหัสผ่านใหม่แล้ว สามารทำ manual reset password ได้โดย

  1. เปิดไฟล์ config/settings.inc.php หาค่าในตัวแปร _COOKIE_KEY_ อันนี้คือตัวแปรที่ prestashop ใช้เป็น salt ครับ
  2. ไปที่ phpMyAdmin เปิดตาราง xxx_employee หาชื่อ user ที่ต้องการ ที่ field password ให้ copy ค่าในตัวแปร _COOKIE_KEY_ ไปวางตามด้วยรหัสผ่านใหม่ที่ต้องการเปลี่ยน จากนั้นในช่อง function เลือก md5 บันทึก รหัสของผู้ใช้ก็จะเปลี่ยนไปตามรหัสที่เราใส่ไปหลังค่าใน _COOKIE_KEY_

ใกล้เลือกตั้งแล้ว เลยจะเขียนอะไรเกี่ยวกับสิทธิดูซักหน่อย สมมุติว่าทำอัลบั้มรูปงานรับปริญญาออนไลน์แต่อยากจะให้สมาชิกดูได้ไม่กี่คน ตามปกติจะมี 3 ตารางคือ ตารางเก็บรูป ตารางสมาชิก และตารางเก็บว่าใครดูได้บ้างอีกตาราง แต่มีเทคนิคที่ทำให้ใช้ 2 ตารางโดยรวมสิทธิไปไว้กับตารางเก็บรูปเลย ก่อนอื่นสร้างตารางก่อน

--
-- Table structure for table `images`
--

CREATE TABLE IF NOT EXISTS `images` (
  `imageId` int(11) NOT NULL AUTO_INCREMENT,
  `src` varchar(20) NOT NULL,
  `assign` varchar(100) NOT NULL,
  PRIMARY KEY (`imageId`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

--
-- Dumping data for table `images`
--

INSERT INTO `images` (`imageId`, `src`, `assign`) VALUES
(1, 'Graduate.jpg', '2,3,15,19');

สร้างตารางสมาชิกเองนะครับ ^_^ ค่าใน assign คือ id ของ user แต่ละคนคั่นด้วย , เวลาแสดงก็หาได้โดยใช้ไอดีของ user มาใส่ใน function FIND_IN_SET ช่วยเลือกข้อมูลตามตัวอย่าง

SELECT  `imageId` ,  `src` 
FROM  `images` 
WHERE FIND_IN_SET(  '3',  `assign` ) > 0;

ถ้า id 3 มีอยู่ใน assign ก็จะเห็นข้อมูลครับ


หลายคนคงบอกว่า ง่ายๆ ไปปิด remote ซะจบ แต่ถ้ายังต้องใช้ก็มีเคล็ดลับอยู่

  1. โดยในช่อง search ในเมนูให้พิมพ์ compmgmt.msc แล้วเอ็นเทอร์
  2. Computer management ก็จะเปิดขึ้นมา ไปที่ Local Users and Groups > users เลือก user ที่เราจะให้ remote ได้ คลิกขวา ในช่อง Full name: ใส่ชื่อใหม่เข้าไป สมมุติว่า doraemon กด apply กด ok
  3. logout ออกไปก่อน login เข้ามาใหม่ user เดิมจะหายไป ไม่ต้องตกใจครับ เพราะมันเปลี่ยนชื่อเป็น doraemon ไปแล้ว ส่วนข้อมูล รูป ไฟล์อะไรต่างๆ ของเรายังอยู่เหมือนเดิม
  4. ไปทดลอง remote เครื่องของเราจากเครื่องอื่น จะใช้โปรแกรมตาม Remote mac Linux windows mobile ก็ได้้รับรองว่าถ้าใช้ user doraemon ถึงรู้รหัสผ่าน สะกดถูกทุกตัวก็เข้าไม่ได้ เพราะความจริงต้องใช้ยูเซอร์เดิมก่อนเปลี่ยนชื่อครับ ปลอดภัยขึ้นอีกนิดหนึ่ง
ติดตาม

Get every new post delivered to your Inbox.

Join 939 other followers

%d bloggers like this: