2015-02-05 19 views
0

我正在構建一個問題spoj.com。用戶必須提交一個腳本,該腳本將預先附加一個我的代碼,以便爲他提供他必須使用的功能。這種類型的模板:隱藏用戶運行腳本的stdin數據?

def youmustusethis(maptask, reducetask): 
    data = sys.stdin.readlines() 
    return reduce(reducetask, map(maptask, data)) 

##### USER WRITES CODE BELOW ##### 
.... 

有趣的是:用戶往往是黑客輸出比解決問題的方式。我預計人們會忽略這些功能,直接讀取stdin,並完全忽略我提供的「框架」。

有沒有一種方法可以強制使用我的框架來處理腳本,從腳本的下半部分隱藏stdin數據?

+0

沒有很好的方法來阻止對'stdin'的訪問,但是你總是可以將'sys.stdin'設置爲別的。 –

+0

我不確定我是否理解 - 如果用戶想要解析stdin,爲什麼不讓他們? – mgilson

+0

SPOJ是一個解決問題的網站。我需要驗證用戶是否學會了如何使用某個框架(MapReduce)。當你寫考試時,你會得到你應用的方法的評分,而不是「答案是5」。我需要強制執行。 – ArekBulski

回答

1

我的建議是 - 不要。爲了使其正常工作,您需要考慮很多事情。請看下面的代碼片段:

sys.stdin = open("/dev/stdin") 

隨着ctypes,這可能會更加困難。與其試圖混淆相當大的攻擊媒介,我建議尋找某人已經創建的沙箱/限制Python環境。我的猜測是,IRC機器人庫應該已經正確地做到了這一點。

+0

我發現它更糟。用戶可以將數據泄露出映射器,在「框架」之外處理它,然後通過減速器泄漏數據。 – ArekBulski

2

這似乎是一個奇怪的要求。你應該寫一個說明「不要訪問sys.stdin」或類似的東西。

關閉我的頭頂,你可以關閉sys.stdin,或重新分配它。 例如:

_stdin = sys.stdin 
sys.stdin = None 

[編輯:我覺得我應該指出,這通常是一個壞主意。]

+0

我認爲保存原來的'sys。stdin「,但由於它看起來像用戶可以讀取原始代碼,我認爲這隻會導致他們訪問'_stdin'。 –

+1

(然後再次,'sys .__ stdin__'總是'stdin',所以......) –

+0

Adam是正確的。 Python不會阻止對「私有」變量的訪問,因此用戶可以隨意查找任何可以找到的變量。 – ArekBulski

2

你可以這樣做:

import sys 
try: 
    import StringIO as io # python2 
except ImportError: 
    import io    # python3 

# your functions go here 

sys.stdin = io.StringIO() 

這將使正常如果您的用戶嘗試使用stdin,但文件操作不會失敗。但是,這可能會讓用戶難以診斷。

比較:

def fails_loudly(): 
    """throws AttributeError""" 
    sys.stdin = None 
    return sys.stdin.read() 

def fails_silently(): 
    """returns empty string""" 
    sys.stdin = io.StringIO() 
    return sys.stdin.read() 
+2

警告一句話......「不失敗,但不能通過」的事情往往很難調試;-)。 – mgilson

+1

同意,但這可能是預期的結果! :) –

+0

謝謝你,亞當。對我來說這是一個有趣的教訓。不幸的是,這似乎無法解決眼前的問題。我需要將stdin數據存儲在某處,以便能夠處理它,同時阻止從下面的用戶代碼訪問它。我不應該阻止自己訪問它。 xP – ArekBulski

0

我發現了一個可能的解決方案。顯然,我可以給用戶一個模板和預先附加不同的模板(略有不同),因此,我告訴用戶「使用」:

def youmustusethis(maptask, reducetask): 
    data = sys.stdin.readlines() 
    return reduce(reducetask, map(maptask, data)) 

##### USER WRITES CODE BELOW ##### 

而我預先追加類似:

def youmustusethis(maptask, reducetask): 
    DATA_48fsnk29s73kdhx7292k = sys.stdin.readlines() 
    return reduce(reducetask, map(maptask, DATA_48fsnk29s73kdhx7292k)) 

##### USER WRITES CODE BELOW ##### 

注意代碼是由SPOJ判斷運行的,用戶只顯示AC/WA,沒有stdout或stderr。除非用戶可以猜出變量名稱,否則他很難找到它。