ในบทความนี้ เราจะเรียนรู้เกี่ยวกับวิธีที่ฟังก์ชัน input ทำงานอย่างไม่พึงประสงค์ในเวอร์ชัน 2.x หรือเวอร์ชันก่อนหน้า ในเวอร์ชัน 2.x ฟังก์ชัน raw_input() ทำงานแทนฟังก์ชัน input() ในเวอร์ชันใหม่ 3.x หรือใหม่กว่า ฟีเจอร์และฟังก์ชันที่พึงประสงค์ของทั้งสองฟังก์ชันถูกรวมเข้าด้วยกันในฟังก์ชัน input()
ก่อนอื่น มาดูประเภทอินพุตของฟังก์ชัน built-in สำหรับรับอินพุตใน Python 2.x
ตัวอย่าง
# Input Given : String
str1 = raw_input("Output of raw_input() function: ")
print type(str1)
str2 = input("Output of input() function: ")
print type(str2)
# Input Given : Float
str3 = raw_input("Output of raw_input() function: ")
print type(str3)
str4 = input("Output of input() function: ")
print type(str4)
# Input Given : Integer
str5 = raw_input("Output of raw_input() function: ")
print type(str5)
str6 = input("Output of input() function: ")
print type(str6)
ผลลัพธ์
Output of raw_input() function: Output of input() function: Output of raw_input() function: Output of input() function: Output of raw_input() function: Output of input() function:
คำอธิบาย − จากผลลัพธ์ มันชัดเจนว่า raw_input function แปลงอินพุตเป็น string type อย่างชัดเจน ไม่ว่าจะเป็นประเภทอินพุตที่ให้มา ส่วน input function จะเก็บชนิดข้อมูลเดียวกับที่ให้มาในขณะอินพุต
ตอนนี้หลังจากเห็นตัวอย่างข้างต้น คุณอาจสงสัยว่า ถ้า input function เก็บชนิดข้อมูลไว้ ทำไมมันถึงเป็นช่องโหว่? มาทำความชัดเจนด้วยภาพประกอบ −
ILLUSTRATION 1: ตอนนี้มาสร้างเกมทอยลูกเต๋าโดยใช้โมดูล random
ตัวอย่าง
import random as rd
number = random.randint(1, 6)
print("Pick a number between 1 to 6")
while True:
user_input = input("Guess the number: ")
if user_input == number:
print("You guessed it right.")
break
else:
print("OOPS! try it next time.")
continue
คำอธิบาย − ในกรณีที่ผู้ใช้ให้อินพุตเป็น integer ผลลัพธ์ที่พึงประสงค์ตามนิพจน์เงื่อนไขจะถูกคำนวณตามลำดับ
ในกรณีที่ผู้ใช้ให้อินพุตเป็น string ที่เหมือนกับชื่อตัวแปรที่เราเก็บจำนวนสุ่มที่ได้จากลูกเต๋าโดยใช้ random module ผลลัพธ์ก็จะถูกคำนวณเช่นกัน แต่สิ่งนี้ไม่ควรเป็นผลลัพธ์ที่พึงประสงค์ที่เราต้องการคำนวณ จริงๆ แล้วมันควรยกข้อยกเว้นเกี่ยวกับประเภทอินพุตผิดเมื่อให้ string input มันพิจารณาว่าชื่อตัวแปรเทียบเท่ากับตัวเลขที่ผู้ใช้ป้อนโดยตรง นิพจน์ให้ค่า Boolean True และเกมจบสิ้นสุด ในทางตรงข้าม ถ้าเราใช้ raw_input() แทน ปัญหาแบบนี้จะไม่เกิดขึ้น
ช่องโหว่นี้อาจเป็นอันตรายถึงชีวิตในกรณีที่เราเก็บข้อมูลล็อกอิน (login credentials), รายละเอียดผู้ใช้ และรหัสผ่านบัญชี
ILLUSTRATION 2: ตอนนี้มาสร้างระบบที่ขอ PIN และเปรียบเทียบกับค่าที่เก็บไว้
ตัวอย่าง
stored_value = 7863
def return_function():
return stored_value
inp = input()
if inp == stored_value:
print "You Entered Correctly"
else:
print "Oops! It's Incorrect"
คำอธิบาย
เช่นที่เราอภิปรายใน ILLUSTRATION ก่อนหน้า ว่าในกรณีที่อินพุตเป็น integer function จะทำงานปกติ แต่ในกรณีใดก็ตามที่ผู้ใช้ให้อินพุตเหมือนกับค่าที่คืนจากฟังก์ชัน เงื่อนไขจะกลายเป็น True และผลลัพธ์จะถูกสร้างขึ้น
สิ่งนี้เป็นอันตรายมากถ้าใช้ในกรณีจัดการข้อมูลสำคัญและเป็นความลับ เช่น PIN และรหัสผ่าน สามารถแก้ไขได้โดยใช้ raw_input() ที่มีใน Python 2.x
จาก ILLUSTRATION ทั้งสองข้างต้น ชัดเจนว่า input function ทำให้โปรแกรมพร้อมสำหรับการโจมตีตัวแปรโดยตรง (Variable attack)
สรุป
ในบทความนี้ เราได้เรียนรู้ว่ามีปัญหาและช่องโหว่อะไรบ้างที่พบขณะใช้ฟังก์ชัน input() ใน Python 2.x ที่จำเป็น