Linux GHOST 安全漏洞修補

二月 12, 2015

這個應該算是有一些時間的新聞了

漏洞的詳細說明及修補的方式:

How To Patch and Protect Linux Server Against the Glibc GHOST Vulnerability # CVE-2015-0235

漏洞是否修補的測試:

Glibc: GHOST Vulnerability Test To See If a Linux Sever Is Secure

另外,說明一下

lsof | grep libc | awk '{print $1}' | sort | uniq

只能列出出目前系統上「正在使用」且「使用到 glibc 」的程式,例如 apache 雖然有安裝在系統上,但是沒有啟動這個服務的話,用上面這個指令是無法列出來的。

可以的話,還是直接 yum update 升級到新的版本吧

另外,因為 glibc 是系統底層的函式庫,最好要將伺服器「重開機」才可以完全的修補,避免有些系統服務沒有重新啟動,而繼續使用到存在記憶體中有安全問題的 glibc

相關網站:
Linux Glibc GHOST 漏洞偵測、修補 CVE-2015-0235


PHP 實作支援 http 續傳功能及如何進行測試

一月 14, 2015

檔案續傳在下載大檔案的時候,非常的實用,在實作時,需要伺服器端及客戶端程到兩者的互相搭配才行。

HTTP 續傳的原理,簡單說明如下:

用戶透過在 request 中加上 Range: bytes=0-499 的 header 給伺服器指定要取得檔案第 0 到 499 個檔案 position 的資料,(共 500 bytes, 第一個 byte 是 postion = 0, 包含第 499 position 位置的資料),在伺服器的回應中,會有

網站內文的程式碼,如下,用戶可以透過使用 Range header 指定伺服器下載檔案指定的檔案片段資料 Content-Range: bytes 0-499/1000000 告知客戶端程式,此次回傳的資料是位於檔案 position 0 到 position 499 的資料,檔案的總長度為 1000000 bytes。客戶端就可以按照對應的位置,把資料寫回檔案中,完成檔案的續傳。

也可以在 request 中指定 Range: bytes=500- 的方式,不指定結束的 position,代表要抓取由 500 position 開始到檔案結束的所有資料。

之前使用 PHP 撰寫檔案下載的程式,但是想要增加支援大檔案的續傳,發現下列這篇文章,內附的範例程式碼如下:

Output a file with HTTP range header in PHP

<?php
  $filename=$_GET['filename'];
  $location='media/'.$filename;
  
  $extension = substr(strrchr($filename,'.'),1);
  if ($extension == "mp3") {
    $mimeType = "audio/mpeg";
  } else if ($extension == "ogg") {
    $mimeType = "audio/ogg";
  }
  if (!file_exists($location))
  {
    header ("HTTP/1.1 404 Not Found");
    return;
  }
  
  $size  = filesize($location);
  $time  = date('r', filemtime($location));
  
  $fm = @fopen($location, 'rb');
  if (!$fm)
  {
    header ("HTTP/1.1 505 Internal server error");
    return;
  }
  
  $begin  = 0;
  $end  = $size - 1;
  
  if (isset($_SERVER['HTTP_RANGE']))
  {
    if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches))
    {
    $begin  = intval($matches[1]);
    if (!emptyempty($matches[2]))
    {
      $end  = intval($matches[2]);
    }
    }
  }
  if (isset($_SERVER['HTTP_RANGE']))
  {
    header('HTTP/1.1 206 Partial Content');
  }
  else
  {
    header('HTTP/1.1 200 OK');
  }
  
  header("Content-Type: $mimeType");
  header('Cache-Control: public, must-revalidate, max-age=0');
  header('Pragma: no-cache');  
  header('Accept-Ranges: bytes');
  header('Content-Length:' . (($end - $begin) + 1));
  if (isset($_SERVER['HTTP_RANGE']))
  {
    
    header("Content-Range: bytes $begin-$end/$size");
  }
  header("Content-Disposition: inline; filename=$filename");
  header("Content-Transfer-Encoding: binary");
  header("Last-Modified: $time");
  
  $cur  = $begin;
  fseek($fm, $begin, 0);
  
  while(!feof($fm) && $cur <= $end && (connection_status() == 0))
  {
    print fread($fm, min(1024 * 16, ($end - $cur) + 1));
    $cur += 1024 * 16;
  }

在 linux 伺服器上進行測試時,可以使用

curl -v -i 'http://yoursite.com/' -H 'Range: bytes=0-499' > ouput_test.mp3

的方式進行檔案續傳的測試,-i 是在下載回來的結果中,同時顯示 http response header 的部分,若是不要顯示 header,可以去除 -i 參數, 或是改用 -v,只把執行的 request header 及 response header 顯示在 console,不顯示在 output_test.mp3 檔案中

若是不用取得 http response body 的部分,只要 header ,可以使用 -I 參數,實際上是使用 http HEAD command 去詢問 web server 取得結果。
如果使用 -I 透過 http HEAD command 取得檔案資料,則 Content-Length header 不一定會出現,這個是看 web server 如何處理,如果是靜態檔案,可以會有這個 header,如果是碰到像 php 這樣動態檔案的話,就不會出現 Content-Length 了,若是想要在 response 中取得原來檔案的完整大小,可以改取 Content-Range header, 如下:

Content-Range: bytes 0-499/1000000

後方的 /1000000 代表的就是原檔案大小為 1000000 bytes (1M)

附上我修改後的程式碼,供參考:

<?php
    
    $file_name_not_secure = $_GET["file_name1"]; //remember to remove '/'
    
    $file_name = str_replace("\r", "", $file_name_not_secure); //replace '\r' for security issue
    $file_name = str_replace("\n", "", $file_name_not_secure); //replace '\n' for security issue
    $file_name = str_replace("/", "", $file_name_not_secure);  //replace '/' for security issue
    
    $file_name_urlencoded = rawurlencode($file_name);
    
    $file_path = "/download/" . $file_name;
    
    if (!file_exists($file_path)) {
        header("HTTP/1.1 404 Not Found");
        return;
    }
    
    $file_size = filesize($file_path);
    
    $start = 0;
    $end = $file_size-1; //because the range spec is zero based.
    
    $dlFile = @fopen($file_path, 'rb');
    if (!$dlFile) {
        header ("HTTP/1.1 500 Internal server error");
        return;
    }
    
    $partialContent = false;
    if (isset($_SERVER['HTTP_RANGE'])) {
        $partialContent = true;
    
        preg_match('/bytes=(\d+)-(\d+)?/', $_SERVER['HTTP_RANGE'], $matches);  //note: bytes=-500 are not supported
        $start = intval($matches[1]);
        if (!empty($matches[2])) {
            $end = intval($matches[2]);
        }
    }
    
    if ($partialContent) {
        header('HTTP/1.1 206 Partial Content');
    } else {
        header('HTTP/1.1 200 OK');
    }
    
    //control proxy not cache this file
    header('Pragma public');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Cache-Control: private', false);
    
    $time  = date('r', filemtime($file_path));  //use RFC 2822 format, Example: Thu, 21 Dec 2000 16:01:07 +0200
    
    header("Last-Modified: $time");
    header('Content-Type: audio/x-wav');
    header('Accept-Ranges: bytes');  //tell http client that the site support Range header
    
    header("Content-Range: bytes {$start}-{$end}/{$file_size}");
    
    if ($partialContent) {
        header('Content-Length: ' . ($end-$start) + 1);
    } else {
        header('Content-Length: ' . $file_size);
    }
    
    //if the filename contains UTF-8 characters
    $user_agent = $_SERVER['HTTP_USER_AGENT'];
    $pos_IE60 = strpos($user_agent, "MSIE 6.0");
    $pos_IE70 = strpos($user_agent, "MSIE 7.0");
    $pos_safari = strpos($user_agent, "Safari");
    if ( $pos_IE60 > 0 || $pos_IE70 > 0 ) {
        header('Content-Disposition: attachment; filename=' . $file_name_urlencoded . '');
    } else if ( $pos_safari > 0 ) {
        header('Content-Disposition: attachment; filename=' . $file_name . '');
    } else {
        header('Content-Disposition: attachment; filename*=UTF-8\'\'' . $file_name_urlencoded . '');
    }
    header('Content-Transfer-Encoding: binary');
    
    //output file content
    $cur = $start;
    fseek($dlFile, $start, 0);  //skip to the right position
    while(!feof($dlFile) && $cur <= $end && (connection_status() == 0)) {
        print fread($dlFile, min(1024 * 16, ($end - $cur) + 1));
        $cur += 1024 * 16;
    }
    
?>

參考資料:
206 / PARTIAL CONTENT


在 CentOS 6 上設定 NFSv4

一月 8, 2015

因為要設定 firewall 的 port 的問題,想要改用 NFSv4 的 protocol,因為 NFSv4 只需要使用到 2049 port,不像是 NFSv3 還會需使用到 RPC portmap RPC bind (port 111) 以及 RPC mounted 的 port (random port),這在防火牆的設定是,是非常困擾的,會需要另外進行設定,讓 RPC 服務將 port 開在指定的地方,才方便進行防火牆的設定

CentOS 5 和 6 是可支援 NFSv4 的,

設定的方式可以參考:

http://www.gtwang.org/2012/02/nfsv4.html

http://www.cyberciti.biz/faq/centos-fedora-rhel-nfs-v4-configuration/

https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Storage_Administration_Guide/s2-nfs-nfs-firewall-config.html

的說明,在這裡大致上說明一下如何設定。

首先,nfs-utils 要安裝好
執行 mkdir /exports 建立給 NFSv4 使用的虛擬目錄
建立要分享的目錄的掛載點,例如我要分享 share 目錄,先建立 /exports/share
再使用 mount --bind /home/share /exports/share 掛載要分享的目錄到 /exports 的掛載點下
可以將這個設定寫入 /etc/fstab 中,讓電腦開機時自動掛載:

/home/share /export/users none bind 0 0

設定 /etc/exportfs 檔案:

/export *(rw,fsid=0,no_subtree_check,sync)
/export/share 192.168.1.0/24(rw,nohide,insecure,no_subtree_check,sync)

重新 export 目錄,執行 exportfs -rv

修改 /etc/sysconfig/nfs 檔案如下,不使用 NFSv2 NFSv3 protocol:

# grep -v "^#" /etc/sysconfig/nfs
MOUNTD_NFS_V2="no"
MOUNTD_NFS_V3="no"
RPCNFSDARGS="-N 2 -N 3"

執行 /etc/init.d/rpcbind start (CentOS 6 需要)
執行 /etc/init.d/nfs start

以上,完成 server 端的設定

其實 /etc/init.d/rpcbind 如果在 linux kernel 3.14 之後,是不需要的,原因請看下列的網址:
http://serverfault.com/questions/530908/nfsv4-and-rpcbind

進行 client 端的設定
使用 mount -t nfs4 server:/ /mnt/nfs
指令來 mount server 分享的空間

也可以將這個設定放在 /etc/fstab 中,在開機時自動 mount:

server:/share /mnt/nfs nfs4 defaults 0 0

firewall 只要開啟 port 2049 就可以連上 NFS 伺服器
以上,完成設定


Linux 檔案系統在權限列表後的小數點

一月 8, 2015

今天在看伺服器的時候,發現檔案後有些有 “.",例如 drwxr-xr-x.  ,有些檔案又沒有小數點接在檔案的權限資料後方,

查了一下資料,What does a period in the file permissions mean? 這篇文章說到,這個是與 selinux 相關的設定。

如果該檔案有相對應的 selinux context,後方就會接著一個小數點,如果有 acl 的權限設定,則是會接著一個 “+" 表示。


CentOS 7 網路卡介面命名方式更改

十一月 19, 2014

最近安裝了一個 centos 7 的機器,發現網路上的命名方式更改了,不再是 ethX 的方式,相關說明以及如何改回舊的命名方式如下:

How to change a network interface name on CentOS 7


Android 2.3 版 Data Table 查出來的資料少了 HAS_PHONE_NUMBER 欄位

八月 5, 2013

在寫查詢裝置上的聯絡人資料時,發現在 Android 4.1 上測試的時候,可以正常的透過 HAS_PHONE_NUMBER = 1 的條件,只列出含有電話號碼的聯絡人,但是後來在 Android 2.3 上測試的時候,因為查詢結果少了 HAS_PHONE_NUMBER 每次查詢都會造成程式錯誤當….

解決方式很簡單,就是去掉這個查詢限制,並且手動用程式檢查聯絡人資料中是否有包含電話號碼…

參考資料:
[1] Android API 8 , 10 ContactsContract.Data.HAS_PHONE_NUMBER no such column


Android ListView item 包含 button 或 checkbox 時,會阻止 onclick event

八月 5, 2013

目前在 Android 4.0.4 的手機上測試 ExpandalbeListView 時,發現如果 list item 中有包含 checkbox 或是 button 時,會阻止 expandablistview 中 onGroupClick 或是 onChildClickEvent 事件不能正確的觸發。

尋找網路上的文章,有提到如果 list item 中有 checkbox 或是 button 存在時,要把 checkbox 或是 button 的 android:focusable 設為 false,才可以讓 list item 的 onclick 事件正常的傳遞到 listview 或是 expandablelistview 中。

相對的,也可以反向利用這個特性,如果在程式運作中,想暫時關閉 listview 中某一個 item 的 onclick 事件及顯示效果(點下去會有高亮度反白)的效果時,也可以暫時將 checkbox 的 focusable 屬性設為 true,就可以達成關閉 onclick 事件的效果。

參考資料:
[1] Android – CheckBox blocks ExpandableListView.OnGroupClickListener
[2] Android – Two onClick listeners and one button


關注

有新文章發表時,會立即傳送至你的收信匣。