麻辣家族討論版版's Archiver

小誌 發表於 2010-5-23 23:20

(實戰專題) 線上票選 防止作票篇

在之前所介紹的『線上票選』範例,各位看倌是否發現了一些問題?例如:當我們選擇好理想的人選,按下『投下神聖的一票』按鈕後,程式處理資料完畢後又自動轉向連結回到投票程式網頁畫面,但此時網頁中那個『投下神聖的一票』的按鈕不見了,這就是我們防止重複投票的過濾機制,但是,當我們關閉瀏覽器然後再重新開啟瀏覽器連結投票程式網頁時,您將會發現又可再次進行投票動作了,怎會這樣!?

 還記得之前美國某個網站對兩岸關係做網友投票時所發生的做票事件嗎?那就有心人士利用程式控制瀏覽器的開啟與關閉而進行做票的行為!對於一般性的票選還無所謂,若是重要的事項票選,例如我們的模範生票選這等重要的事項可就得注意了!!


[color=DarkOrange][size=5][b]讀取資料錄[/b][/size][/color]
還記得小誌在『線上票選』的利用說明中特別強調:資料庫中的欄位名稱可自行修改,更改欄位名稱後,必須將程式網頁vote.asp及更新票選結果程式votesave.asp中的欄位名稱設定一同變更!那有沒有辦法修改資料庫中的欄位名稱後,不需要再變更程式網頁vote.asp及更新票選結果程式votesave.asp中的欄位名稱呢?答案是肯定的。

每一筆資料錄就是一個列位,每一筆資料錄由許多的資料欄位(Field)所組成,Field物件有三個重要的屬性:Name(資料欄位抬頭)、Value(資料欄位的資料內容)、Type(資料欄位的資料型別)。

[attach]820[/attach]

[color=Magenta]抬頭列位是用來作為資料讀取的位置判斷條件![/color]

資料錄是Fields集合物件,也就是說它是一個『陣列』的型式:

[attach]821[/attach]

因此,我們要讀取資料庫中資料表的各欄位抬頭名稱可利用下列方法:[code]RS(i).Name '列出欄位抬頭[/code]如果要讀取資料欄位的資料內容(Value),則可利用下列方法:[code]RS(i).Value '列出欄位資料內容[/code][color=Red][b]提示[/b][/color]
假設我們資料錄內含的資料欄位數量有10個,則資料錄內含的資料欄位是由0開始編號到9為止共十個喔!上例中 i 就是資料欄位的編號。

小誌 發表於 2010-5-23 23:24

為了當我們更改資料庫資料表中的資料錄欄位名稱之後,不必再修改相關的程式網頁,因此我們必須變更網頁中讀取資料錄欄位的程式敘述。

之前,我們在計算計算總投票數(下圖綠色部分程式敘述),以及計算各個候選人的得票圖片寬度屬性Width設定值(下圖藍色部分程式敘述),都是利用指定資料錄欄位『抬頭名稱』的方式!所以一旦更改了資料庫資料表中的資料錄欄位名稱,相對地也就必須更改網頁中的程式敘述!

[attach]822[/attach]

因此,為了改善這個缺失,我們可以將上圖中的程式敘述更改成下圖這種方式:

[attach]823[/attach]

[color=Red]注意
RS(0)代表讀取目前動作資料錄中第1個欄位中的資料內容;RS(1)代表讀取目前動作資料錄中第2個欄位中的資料內容,以此類推![/color]


在計算好各個候選人的得票圖片寬度屬性Width設定值後,在圖形顯示與票數顯示的部分我們原先採用下圖的方式。

[attach]824[/attach]

你可以發現:
[list]
[*]圈票處表格欄位中的表單元件選擇鈕所傳送的值(Value)是固定的(如上圖中的 value="康小明")。
[*]同時,在候選人表格欄位中,候選人的名稱則是固定的(如上圖中的第二列 <td>康小明</td>)。
[*]在得票數顯示的部分同樣採取指定資料錄欄位『抬頭名稱』的方式!
[/list]

修正程式如下圖:

[attach]825[/attach]

[color=Red]提示
候選人表格欄位與圈票處表格欄位中的表單元件選擇鈕所傳送的值(Value)都是資料錄欄位的『抬頭名稱』;而得票數顯示的部分則是資料錄欄位的『資料內容』![/color]

小誌 發表於 2010-5-23 23:31

[color=DarkOrange][size=5][b]應用Session與Cookies[/b][/size][/color]
[color=Green][size=4][b] Session物件 [/b][/size][/color]
 Session物件是一個將瀏覽者相關資訊紀錄於Server端的物件,每一個連線者都可在Server端擁有屬於自己的獨立Session物件,瀏覽者的Session物件生命消失於瀏覽者在一定的時間內沒有再與Server端聯繫(例如索取網頁資料等),或者是瀏覽者的瀏覽程式關閉了,這兩項都是我們『線上票選』程式的致命傷,這兩個因素都會使我們防止重複投票的過濾機制失效。

 我們原本在程式中設定了變數名稱為checkvote的Session物件,如果其資料值為"yes"代表投過票了,與決定顯示『投下神聖的一票』按鈕與否的Session物件變數『checkvote』,如果其資料值為『no』代表不顯示投票按鈕。

[attach]826[/attach]

這兩個Session物件變數將會消失於瀏覽者的瀏覽程式關閉,或者是瀏覽者在一定的時間內沒有再與Server端聯繫,就因為如此而出現了做票的漏洞。


[color=Green][size=4][b] Cookies物件 [/b][/size][/color]

 Cookies物件則是一個將瀏覽者相關資訊紀錄於Cliner端的物件,也就是說每一個瀏覽者的相關資訊是紀錄在自己的機器中,因此就算瀏覽者的瀏覽程式關閉,或者是瀏覽者在一定的時間內沒有再與Server端聯繫,這些相關的資訊都不會消失,當瀏覽器再度被啟動時,這些相關的資訊也會再度的被瀏覽器讀取與利用。

Cookies物件的寫入資料與讀取資料跟Session物件可是大不相同喔!所謂讀取Cookies物件的資料是指從瀏覽者瀏覽器中取回Cookies物件變數的值;而寫入Cookies物件的資料則是指將Cookies物件變數的值放在瀏覽者瀏覽器中(其實是存放在瀏覽者機器中的某個檔案裡)。

 Cookies物件的寫入動作是必須透過Response物件來達成的,因此我們將Cookies物件變數的值放在瀏覽者瀏覽器中所使用的敘述如下:[code]Response.Cookies("Cookies物件變數名")="寫入的資料"[/code] Cookies物件的讀取動作則是必須透過Request物件來達成的,因此我們將放在瀏覽者瀏覽器中Cookies物件變數的值取回程式中使用則必須使用下列格式的敘述:[code]Request.Cookies("Cookies物件變數名")"[/code][attach]827[/attach]

[b][color=Red] Cookies使用注意事項[/color][/b]
[list]
[*]要將Cookies物件的資料寫入到瀏覽者瀏覽器中之前,必須沒有任何的資料(大部分都是HTML網頁標籤)先被傳送到瀏覽者的瀏覽器。
[*]瀏覽者瀏覽器的Cookies功能必須是開啟的,幸好IE5已經取消了關閉瀏覽器的Cookies的選項。
[*]Cookies物件不能在不同的瀏覽器中使用,例如使用於IE瀏覽器的Cookies物件NC瀏覽器不能使用;使用於NC瀏覽器的Cookies物件IE瀏覽器不能使用,其主要原因是各個瀏覽器儲存Cookies物件的位置不同之故。
[/list]

知道Cookies物件的使用方法與原則後,接著就來更正我們的投票過濾機制(本例投票程式網頁為vote2.asp):
[attach]828[/attach]
[list]
[*]藍色部分程式敘述為讀取"checkvote"的Cookies物件變數值,若正確的完成投票動作則變數值將會是"yes",所以將顯示於程式網頁中的訊息文字字串設定為『你已經投過票了!只能觀看投票結果!』,並且將決定顯示『投下神聖的一票』按鈕與否的確認變數『checkvote』設定為『no』代表不顯示投票按鈕。
[*]紅色部分程式敘述為讀取"er"的Cookies物件變數值,若未正確的完成投票動作則變數值將會是"no",所以將顯示於程式網頁中的訊息文字字串設定為『之前的投票無效,請選擇一位候選人投票』,並且將決定顯示『投下神聖的一票』按鈕與否的確認變數『checkvote』設定為『yes』代表顯示投票按鈕。
[*]綠色部分程式敘述則為前兩段敘述條間都不成立時才會執行,若尚未進行過投票動作(包含未正確的完成投票動作)則寫入"checkvote"的Cookies物件變數值"yes",顯示於程式網頁中的訊息文字字串設定為『你的一票選模範生』,並且將決定顯示『投下神聖的一票』按鈕與否的確認變數『checkvote』設定為『yes』代表顯示投票按鈕。
[/list]


[color=Green][size=4][b]加上"er"的Cookies物件變數用意:[/b][/size][/color]
既然是攸關勝敗的模範生重要票選,因此我們不能在某位候選人的圈選欄位上設定為預設選項,以避免有誤導之嫌,但是若選舉人若沒有圈選任何一位候選人而按下投票按鈕,則雖然沒有任何一位候選人獲得選票,但是卻失去了票選的意義,因此我們才多設置了未正確的成投票動作的過濾機制。
Vote2.asp[code]<%
er=Request.Cookies("er")
IF err="" then err=empty
'建立資料庫連結物件
        Set conobject = Server.CreateObject("ADODB.Connection")
        DBPath = Server.MapPath("vote.mdb")
'連結資料庫       
        conobject.Open "Driver={Microsoft Access Driver (*.mdb)};DBQ="&DBPath
'建立資料庫存取物件       
        Set RS=Server.CreateObject("ADODB.Recordset")
'打開資料表       
        RS.Open "Select * from student",conobject,0,1
       
'計算總投票數與設定得票率圖表寬度        
        VotePeople=RS(0)+RS(1)+RS(2)+RS(3)
IF RS(0)>0 then linelong1= 500*RS(0)/VotePeople
IF RS(1)>0 then linelong2= 500*RS(1)/VotePeople
IF RS(2)>0 then linelong3= 500*RS(2)/VotePeople
IF RS(3)>0 then linelong4= 500*RS(3)/VotePeople

'投票檢查
IF Request.Cookies("checkvote")="yes" then
msg="你已經投過票了!只能觀看投票結果!"
VoteButton="no"
ElseIF er="yes" Then
Response.Cookies("er")="no"
msg="之前的投票無效,請選擇一位候選人重新投票"
VoteButton="yes"
Else
Response.Cookies("checkvote")="yes"
msg="你的一票選模範生"
VoteButton="yes"
End IF
%>
<CENTER>
<P><img border="0" src="logo.gif"><br>
<font color="#0000FF"><%=msg%></font></P>
<form method="POST" action="votesave2.asp">
  <table border="1">
    <tr>
      <td bgcolor="#FF3399"><font color="#FFFFFF">圈票處</font></td>
      <td bgcolor="#FF3399"><font color="#FFFFFF">候選人</font></td>
      <td bgcolor="#FF3399"><font color="#FFFFFF">得票數</font></td>
    </tr>
    <tr>
      <td align="center">
      <input type="radio" name="vote" value=<%=RS(0).name%>></td>
      <td><%=RS(0).name%></td>
<td><img border="0" src="vote.gif" Height="5" Width=<%=linelong1%>>
       <%=RS(0)%>票</td>
    </tr>
    <tr>
      <td align="center">
      <input type="radio" name="vote" value=<%=RS(1).name%>></td>
      <td><%=RS(1).name%></td>
<td><img border="0" src="vote.gif" Height="5" Width=<%=linelong2%>>
       <%=RS(1)%>票</td>
    </tr>
    <tr>
      <td align="center">
      <input type="radio" name="vote" value=<%=RS(2).name%>></td>
      <td><%=RS(2).name%></td>
<td><img border="0" src="vote.gif" Height="5" Width=<%=linelong3%>>
       <%=RS(2)%>票</td>
    </tr>
    <tr>
      <td align="center">
      <input type="radio" name="vote" value=<%=RS(3).name%>></td>
      <td><%=RS(3).name%></td>
<td><img border="0" src="vote.gif" Height="5" Width=<%=linelong4%>>
       <%=RS(3)%>票</td>
    </tr>
  </table>
<%IF VoteButton="yes" then %>
<p><input type="submit" value="投下神聖的一票"></p>
<% End IF %>
</form>
</CENTER>[/code]

小誌 發表於 2010-5-23 23:34

[color=DarkOrange][size=5][b]投票結果儲存程式[/b][/size][/color]
投票結果儲存程式『votesave2.asp』,在本程式中與第一版的線上票選範例相同,沒有網頁資料的顯示,本程式只負責將投票程式網頁中所傳送過來的投票資料資料更新到資料庫中,然後將連結轉向回投票程式網頁。

[attach]829[/attach]

上圖左半部為原來第一版的線上票選範例的更新投票結果程式區段,右半部則為改良後的『votesave2.asp』更新投票結果程式區段。

下圖為配合投票程式網頁(vote2.asp)中選舉人未正確的完成投票動作而新增的程式敘述:

[attach]830[/attach]

Votesave2.asp[code]<%
vote=Request("vote")
IF vote=empty then
Response.Cookies("er")="yes"
Response.Cookies("checkvote")="no"
Response.Redirect "vote2.asp"
Else
'Response.Cookies("checkvote").Expires="2001/12/31"
Response.Cookies("checkvote")="yes"
'建立資料庫連結物件
        Set conobject = Server.CreateObject("ADODB.Connection")
        DBPath = Server.MapPath("vote.mdb")
'連結資料庫       
        conobject.Open "Driver={Microsoft Access Driver (*.mdb)};DBQ="&DBPath
'建立資料庫存取物件       
        Set RS=Server.CreateObject("ADODB.Recordset")
'打開資料表       
        RS.Open "Select * from student",conobject,1,3
'更新投票結果        

Select case vote
        case RS(0).name
                 RS(0)=RS(0)+1
        case RS(1).name
                 RS(1)=RS(1)+1
        case RS(2).name
                 RS(2)=RS(2)+1
        case RS(3).name
                 RS(3)=RS(3)+1
End Select          
RS.UPdate
End If
Response.Redirect "vote2.asp"

%>[/code][color=Magenta] 使用Cookies物件的原因:[/color]
以線上票選程式來說,可減少做票的情況,但並非是百分之百喔!因為使用者也可以清除他瀏覽器中的Cookies檔案而重新投票!
避免web 伺服器的系統資源浪費,我們知道若使用Session物件,則連線瀏覽者的相關資訊是存放在Web Server端的,而且每個連線瀏覽者都有屬於自己的Session物件,試問若有100位連線瀏覽者同時上線那系統的資源消耗會有多大?


[color=Magenta] 未來研究方向[/color]
  既然使用Cookies物件只能減少做票的情況發生,那有沒有更好的辦法使做票情況發生的可能性降到最低?有的,那就是利用資料庫紀錄連線者的IP,將已經連線投票的IP暫時鎖定起來,目前許多的票選活動都採用此種方式。


[color=RoyalBlue][size=4][b](實戰專題) 線上票選 防止作票篇完整範例壓縮檔:[/b][/size][/color][attach]831[/attach]

Luc 發表於 2010-8-15 00:45

鎖住RemoteAddr是防機器人灌票的好方法。
不過以現在ISP的動態IP及部份使用NAT架構的用戶端... 還是會產生公平性的問題。

頁: [1]

麻辣家族討論版版為 麻辣學園 網站成員  由 昱得資訊工作室 © Since 1993 所提供