BinaryVision

החסן נייד כאסימון זהות

מאת בתאריך 07/11/11, תחת כללי

בפוסט האחרון דיברתי על אמצעי אלחוטי ("שן כחולה") כאסימון זהות, כאשר הסתמכנו על מנגנון ההצפנה המובנה של הפרוטוקול כמנגנון ההגנה המונע זיוף. בפוסט הזה אציג אסימון זהות אשר מבוסס על התקן אשר מתחבר פיזית אל המחשב, גם כאן נבחן את היתרונות והחסרונות של השיטה ונציג דרך יישום יעילה (בלינוקס). אני ממליץ לעבור לפחות על החלק הראשון של הפוסט הקודם בשביל להכיר את היתרונות והחסרונות של שימוש באסימון זהות באופן כללי.

בעוד שניתן למצוא אמצעיים יעודיים למטרה זו, שמציעים רמת אבטחה משתנה ממוצר למוצר ודרכי התמשקקות שונות (חיבורים יעודיים), אנחנו נעשה שימוש בחיבור הזמין כמעט בכל מחשב, חיבור USB, ושימוש במחלקת Mass Storage Device (מעתה MSD), ניתן לעשות שימוש במחלקות אחרות1, אך לרוב הן מסובכות יותר, מצריכות ציפייה יחודית מהמערכת ואקטיביות מסויימת של ההתקן עצמו2.

בחרתי לעשות שימוש ב-MSD בעיקר בזכות הפשטות והזמינות. היכולת ליצור מחיצה מוצפנת, תהפוך את גניבת המפתח הנמצא במחיצה זו למעט יותר מורכבת. אני אזהיר מראש ואציין כי יש לזכור שהמפתח הוא סטטי ולמרות שהוא מוצפן, שעתוק מושלם של ההתקן3 יאפשר להתקן המשועתק להכניס את האוחז בו למערכת שלכם. החסרון הבולט ב-MSD שהדו-שיח במחלקה (בין ההתקן למחשב) אינו מוצפן, לכן אנחנו נאלצים להשתמש בשיטות אשר אך ורק יערימו קשיים אך לא יגנו באופן מוחלט על ההתקן4.

כדי ליצור מפתח אשר לא ניתן להעתקה (ברמת התקשורת) צריך להשתמש בלחיצת יד משולשת (המבוססת על Pre shared key) למסירת המפתח הנותן גישה למערכת. (התקן -> מחשב) המחשב מזהה את ההתקן וההתקן מבקש את מפתח A מהמחשב, לאחר שההתקן מקבל את מפתח A, הוא יוצר מחלקת תקשורת חדשה, אשר מקודדת בעזרת מפתח A. (התקן <- מחשב) המחשב מבקש את מפתח B, הוא מתקשר דרך המחלקה החדשה אשר מקודדת בעזרת מפתח A ומקבל מההתקן את מפתח B, שכן מפתח A משפיע על מפתח B, הפלט המתקבל הוא מפתח C והוא יבחן כנגד מפתח C הנמצא במערכת מבעוד מועד, אם הם תואמים תנתן גישה למערכת. [ההתקן מחזיק את מפתח B בלבד, ואילו המחשב מחזיק את מפתחות A ו-C]

כאן אנחנו רואים שאין גישה למפתח B ללא מפתח A ומבחן התאימות הוא בכלל כנגד תוצר של שני המפתחות, ובכך אנחנו זוכים להגנה על מפתח C שנעשה בעזרת הפרוטוקול (ליתר דיוק בעזרת המחלקה). אך עדיין שיעתוק ברמת החומרה, משמע פירוק ההתקן והעתקת המידע הנמצא על שבבי הסילקון להתקן אחר, יאפשר גישה. כזכור, אחד החסרונות של אסימון זהות מסוג זה שהוא ניתן להעתקה, הדבר היחיד שניתן לעשות זה להערים קשיים. אך עתה נעבור למקרה שלנו, וזה שימוש ב-MSD לשם מתן גישה למערכת.

תוך כדי ההדגמה אני אעיר לגבי דברים שצריכים לשים לב אליהם. אז הדבר הראשון שאנחנו נצטרך הוא החסן נייד מבוסס USB (ניתן גם לעשות שימוש בכרטיסי זכרון), השטח שנצטרך ממנו הוא מזערי (לא יותר ממגה בייט) אך אולי נרצה לשים קבצים נוספים על מחיצה זו, אני בחרתי לתת 64 מגה למחיצה המוצפנת (/dev/sdb2) שתשמש אותי לאחסן את המפתח.

# cfdisk /dev/sdb
# mkfs.vfat /dev/sdb2
# dd bs=4096 count=1 if=/dev/urandom of=/root/usb/file.key
# cryptsetup luksFormat -c "aes-cbc-essiv:sha256" --key-file=/root/usb/file.key /dev/sdb2
# cryptsetup luksOpen --key-file=/root/usb/file.key /dev/sdb2 usbkey
# mkfs.vfat /dev/mapper/usbkey
# mount /dev/mapper/usbkey /mnt/usbkey

בשלב זה סיימנו את ההכנה של ההתקן , עתה נעבור להכנת המפתח (קובץ), ניצור קובץ אשר ישמר על המחשב וערך ה-Hash (גבוב) שלו ישמש לפתיחת המחשב, את ערך הגבוב נשמר בקובץ על ההחסן הנייד. הקובץ על המחשב וערך הגיבוב הנשמר על ההחסן הנייד ישתנו בהתאמה בכל התחברות בכדי להפחית מסטטיות המפתח – אך זאת נעשה מאוחר יותר.

# dd bs=4096 count=4 if=/dev/urandom of=/root/usb/passcode
# sha512sum /root/usb/passcode > /mnt/usbkey/0
# umount /mnt/usbkey
# cryptsetup luksClose usbkey
# eject /dev/sdb

אנחנו רוצים שתהליך בדיקת המפתח הנמצא על ההחסן הנייד יבדק רק כאשר אנחנו מחברים החסן נייד מסויים, ובכדי לצמצם את המשאבים הנצרכים ננסה להיות תיאוריים כמה שיותר בחוק udev שנוסיף (ניתן להיעזר בקישור הזה בכדי לזהות את ההתקן שבידכם). יש לשים לב כי המחיצה שבה אני עושה שימוש היא השניה (לכן sd?2).

KERNEL=="sd?2", ATTRS{serial}=="07991E01XXXXXXXX", SYMLINK+="usbkey"
ACTION=="add", ENV{STARTUP}=="1", GOTO="usb-key-end"
ACTION=="add", KERNEL=="sd?2", ATTRS{serial}=="07991E01XXXXXXXX", RUN+="/root/usb/unlock.sh"
LABEL="usb-key-end"
ACTION=="remove", KERNEL=="sd?2", RUN+="/root/usb/lock.sh"

כפי שאנחנו רואים יהיה שימוש בשני סקריפטים5, lock.sh אשר ינעל את המערכת כאשר ההתקן יוצא

#!/bin/sh
# USBKey unlock script

if [ ! -L /dev/usbkey ]; then

	user=`ps aux | grep gnome-screensaver | head -n 1 | awk '{print $1}'`

	if [ -n $user ]; then
		GNOME_SCREENSAVER_PROC=`ps xa | grep gnome-screensaver | head -n 1 | awk '{print $1}'`
		export `grep -z DBUS_SESSION_BUS_ADDRESS /proc/$GNOME_SCREENSAVER_PROC/environ`

		su $user -c "qdbus org.gnome.ScreenSaver /ScreenSaver org.gnome.ScreenSaver.Lock"
	fi
fi

והסקריפט, unlock.sh  יבצע בדיקה של המפתח, הכנסה למערכת ועדכון של המפתח. עדכון המפתח בכל כניסה יאפשר "להשתמש בהתקן רק פעם אחת", משמע אם מישהו שיעתק את ההתקן והוא נכנס איתו למערכת לפניך, אז אתה תחסם ובכך תהיה מודע לכך שמישהו נכנס לך למערכת. ואילו אם אתה תכנס לפניו, ההתקן שיש בידו של האחר חסר ערך6.

סקריפט הפתיחה unlock.sh7 צריך להיות מותאם לפי המערכת שלכם, במקרה שלי יש שימוש במנהל כניסה LightDM ומנהל חלונות Gnome3, ולקחתי בחשבון שני מצבים, (1) שאני אחבר את ההתקן כאשר אני נמצא במסך הכניסה (2) שאני כבר בתוך מנהל החלונות ג'נום. לכל מקרה צריך תגובה שונה של הסקריפט. שיטת הכניסה במקרה הראשון (1) דיי עקומה, אך לא מצאתי דרך להעביר למנהל הכניסה את פרטי הכניסה, אין לי ספק שיש כאן המון מקום לשיפור.

#!/bin/sh
# USBKey unlock script
# Mounting the partition.

COUNT=0

while [ "$COUNT" -lt 5 ]; do
	COUNT=`expr $COUNT + 1`
	sleep 5 # let the drive settle

	if [ -b /dev/usbkey ]; then
		/sbin/cryptsetup luksOpen --key-file=/root/usb/file.key /dev/usbkey usbkey
		PHASE=1
		COUNT=5
	elif [ "$COUNT" = "5" ]; then
		PHASE=0
		echo "`date` Can't find drive." >> /root/usb/access.log
        fi
done

if [ "$PHASE" = "1" ]; then
	if [ -d /mnt/usbkey ]; then
		/bin/mount -o uid=0,gid=0,umask=0177 /dev/mapper/usbkey /mnt/usbkey
	elif [ -d /mnt ]; then
		/bin/mkdir /mnt/usbkey
		/bin/mount -o uid=0,gid=0,umask=0177 /dev/mapper/usbkey /mnt/usbkey
	fi 

# Checking the hash value on the usbkey vs the passcode.

	pass=`sha512sum -c /mnt/usbkey/0|tail -n 1|awk '{print $2}'`

# Logining you in, change 'itzhak' to your own username.

	if [ "$pass" = "OK" ]; then

		user=`ps aux | grep gnome-screensaver | head -n 1 | awk '{print $1}'`

		if [ "$user" = "lightdm" -o "$user" = "root" ]; then
	        	/usr/bin/service lightdm stop
	        	su itzhak -c "startx"

		elif [ -n $user ]; then
		        GNOME_SCREENSAVER_PROC=`ps xa | grep gnome-screensaver | head -n 1 | awk '{print $1}'`
		        export `grep -z DBUS_SESSION_BUS_ADDRESS /proc/$GNOME_SCREENSAVER_PROC/environ`

		        su $user -c "qdbus org.gnome.ScreenSaver / SetActive false"
		fi

# Genereting a new hash and passcode for the next login.

		/bin/dd bs=4096 count=4 if=/dev/urandom of=/root/usb/passcode
		sha512sum /root/usb/passcode > /mnt/usbkey/0

# Closing the partition

	        /bin/umount /mnt/usbkey
		/sbin/cryptsetup luksClose usbkey

# If the passcode miss-match the hash,
# log and unmount

	else
		echo "`date` Some kind of error accoured." >> /root/usb/access.log
	        /bin/umount /mnt/usbkey
		/sbin/cryptsetup luksClose usbkey
	fi
fi

יצרתי סקריפט נוסף אשר יאפס את הסיסמא במקרה שהגבוב הנמצא על ההחסן הנייד לא תואם, זה יכול לנבוע מהסרה לא בטוחה של ההתקן, אם המחשב קרס או אם שכחתם לבצע את הפעולה. לפעמים זה גם קורה כאשר עדיין קיים מיפוי ל-usbkey וניתנה פקודת eject, בעיגון הבא של המחיצה היא תהיה במצב קריאה בלבד, מה שימנע את עידכון הגבוב. הסקריפט הזה נועד אך ורק לשם נוחות.

#!/bin/sh

# Simple Script to re-create the key.
# Make sure the device already connected and it failed to log you in.

# Mounting
/sbin/cryptsetup luksOpen --key-file=/root/usb/file.key /dev/usbkey usbkey
/bin/mount -o uid=0,gid=0,umask=0177 /dev/mapper/usbkey /mnt/usbkey

# Re-creating
/bin/dd bs=4096 count=4 if=/dev/urandom of=/root/usb/passcode
sha512sum /root/usb/passcode > /mnt/usbkey/0

# Unmounting
/bin/umount /mnt/usbkey
/sbin/cryptsetup luksClose usbkey
/usr/bin/eject /dev/usbkey

echo "Wait few seconds and remove the device"
echo "Wait few more, and reconnect it, it should log you into the system"

בפוסט הצגתי איך להשתמש בהחסן נייד כמפתח למערכת שלכם (אסימון זהות), שכן המחלקה MSD אינה מוצפנת בחרתי להצפין את המחיצה, מה שלמעשה אינו מגן מהעתקה מלאה של כל הכונן אשר דיי טריוואלית, לכן הוספתי הסתמכות נוספת על המספר הסיראלי של ההתקן, אך גם מידע זה ניתן לזייף בעזרת חומרה מסויימת. לכן לבסוף המפתח מוחלף בכל שימוש, מה שממזער את הסטטיות של המפתח.

הסקריפטים נכתבו ונבדקו על  ubuntu 11.10, הפצות אחרות כנראה שיצטרכו מעט התאמה של הסקריפטים, בסך הכל הסקריפטים נכתבו במהירות ובאי-הקפדה יתרה, תרגישו חופשי לשפר ולהפיץ,  את הקבצים ניתן למצוא כאן. אני בנוסף אציין את pamusb שלא יצא לי לבחון לעמוק אך היא מציעה מנגנון דומה.

1 YubiKey לדוגמא עושים שימוש במחלקת HID, ההתקן פועל כמקלדת אשר שולחת את השם משתמש והסיסמא למסך ההתחברות.
2 השימוש ב-HID, דימוי למקלדת אשר שולחת את שם המשתמש והסיסמא (נְתוּנֵי הַאֲמָנָה, Credentials) עלול לסכן אותם כאשר הם נשלחים בכל התחברות ללא הבחנה, לכן נדרשת אקטיביות מצד ההתקן בכדי לזהות את המחשב אליו הוא מחובר ואם יש צורך להזדהות (האם נמצאים במסך ההתחברות).
3 שתי הנחות, 1. למישהו יש יכולת לשנות להתקן USB הנמצא ברשותו את המידע הראשוני שהוא מוסר כמו ID, ייצרן, שם, מחלקה וכיוצא בזאת (יש צורך בחומרה מיוחדת, אך לא אקזוטית). 2. לאותו אדם הייתה גישה לפרק זמן קצר להתקן שלכם והוא שיעתק את התוכלה הנמצאת על הכונן (לדוגמה: dd if=/dev/usbkey of=/dev/copy-of-it).
4 בכדי להפוך את המפתח לפחות סטטי וכן מתן בקרה מסויימת עליו אנחנו נחליף את המפתח בכל פעם שהאמצעי מתחבר.
5 שלד הסקריפטים נלקח מהאתר "הבלוג של ג'ון – הבלוג הקטן שלי".
6 יש לשים לב שהוצאה לא סדירה של ההתקן תגרום לשיבוש בשמירה של המפתח ובכך לכשל בכניסה הבאה.
7 אני עושה שימוש בספריה /root שכן ספרית הבית שלי מוצפנת ולא ניגשה מלפני כניסה למערכת, לא התעמקתי בלחפש דרך לגרום לזה לעבוד דרך המחיצה המוצפנת.

:, , , , , , , , , , ,
3 תגובות:
  1. TAsn

    יפה מאוד, אחלה מאמר.

    הערה קטנה: /dev/random יותר ראנדומלי מ /dev/urandom, וזה חשוב במקרה הזה של יצירת מפתח הצפנה.

  2. iTK98

    משום מה /dev/random מחזיר אצלי כמות מידע משתנה ולא קבועה (אני מבקש ממנו 4 מקטעים של 4096 בייטים, סך הכל 16 קילו בייט) הוא מחזיר לי הרבה פחות, היה לי קושי להסתמך על המנגנון הזה בעוד שאני יודע שהוא רנדומלי יותר.

    בכל אופן, אפשר להשתמש בהמון מקורות לרנדומליות, כמו הזכרון, חלק (משתנה מפעם לפעם) מהכונן, ועוד. צריך לזכור שבסופו של דבר המפתח הוא פלט של גיבוב SHA512, ולא הקובץ שנוצר מהאמצעי urandom.

  3. TAsn

    הכי רנדומלי זה /dev/random, אחרי זה, /dev/urandom, כל טריק אחר, הוא לא טוב (או סביר שלא טוב). 🙂

    הבעיה של /dev/random זה שהוא לא מתפשר על הראנדומליות. הוא יוצר את הרנדומליות שלו מ"רעשים". לדוגמה, תנועה של העכבר או הקשה על המקלדת תיצור לו עוד מידע רנדומלי. זה למה כשאתה יוצר מפתחות הצפנה, הרבה פעמים מבקשים ממך להזיז את העכבר ברנדומליות או שטויות כאלה…

    /dev/urandom לעומת זאת, פחות נוקשה, וממחזר מידע במקרה שאין מידע זמין. זה מה שהופך אותו לפחות רנדומלי, אבל יותר שימושי.

השאר תגובה

מחפש משהו?

תשתמש בטופס למטה כדי לחפש באתר: