面試+筆試題目 ==================== ###### tags: `Interview Question` # AES, RSA, AES+RSA # CORS, CSRF, SSRF, XSS ### XSS Cross-Site Scripting 基於使用者對網站的信任 資料從不可信賴的來源 進到後端, 且後端再傳送未經驗證的資料到瀏覽器中, 導致瀏覽器執行惡意的程式碼. XSS攻擊兩大要素: 1. 攻擊者提交惡意代碼 2. 瀏覽器執行惡意代碼: 防止HTML中出現注入HTML/JS, JS執行時避免直接Eval(js) 1. 惡意代碼, 透過後端存入DB, 並且被API撈出來在前端中執行. ![](https://i.imgur.com/xOXAdpp.png) 把代碼做escape. 2. 把釣魚URL含JS, 一樣透過API返回, 用戶只要打開惡意URL就生效. ![](https://i.imgur.com/Wy1pkXD.png) 3. 惡意HTML, 一樣透過API返回, 讓JS渲染. ![](https://i.imgur.com/ruhIAHn.png) ### CSRF Cross-site request forgery : 跨站請求偽造, 利用網站對瀏覽器的信任. 攻擊者可以盜用你的登入資訊, 用你的身份模擬傳送各種請求. ![](https://i.imgur.com/u2r6qFQ.png) 盜用方式, 通常是透過Cookie. 1. 登入受信任網站www.xx.org, 並且在本地產生cookie 2. 在不退出A的情況下, 訪問危險網站B stocks.xx.org 危險網站B, 就能透過cookie, 來取得資訊, 對後端送各種請求. 3. 又或者關閉瀏覽器了, cookie還沒過期,或是session還沒結束. 防範方法: 1. RESTFul 風格, GET不要更改資源狀態, 正確使用GET, POST, COOKIE 2. 在非GET的請求中增加驗證Token或是一次性OTP 3. Http referer檢查, 但有些瀏覽器還是能被串改 CSRF的核心概念,就是銀行不知道發出請求的人是不是攻擊者,那按照這個思路,只要使用者能提出一個唯一且保密的序號,攻擊者拿不到這個序號,自然就不能偽裝成使用者,而這個序號,就是我們稱的CSRF Token,這個Token是由銀行server產生,並且加密存在session中的,其他人無法仿造,只有透過server給使用者,並在一定時間內刷新。當使用者想做任何交易的時候,銀行server就會請使用者提供CSRF Token,如果不能提供,就代表這次的請求就是攻擊者,那銀行server就不予理會。 4. JWT https://www.chainnews.com/zh-hant/articles/600964312027.htm https://www.chainnews.com/articles/618596796644.htm ## 演算法筆試題目 1. 丟出N個骰子,所有骰子朝上一面的點數之和為S。 輸入N,求出S的所有可能的值出現的機率? 2. 印出1~100的質數 3. Decimal Repr Zip ![](https://i.imgur.com/UNzhsaf.jpg) ![](https://i.imgur.com/PSsZ26N.jpg) 4. Four Digits ![](https://i.imgur.com/AzcdqxL.jpg) ![](https://i.imgur.com/vZT7kAL.jpg) ## DB筆試題目 1. How the MySQL index works (innoDB)? 2. What's inner join, outer join, left join and right join? 3. What's the differnce between MyISAM v.s. InnoDB? ``` MyISAM 是Table-level lock, InnoDB是Row-level lock; innodb支援ACID ``` 4. count(*) and count(1). which performance is better?```https://zhuanlan.zhihu.com/p/28397595``` 5. What's the difference between partition v.s. sharding?```1. https://like-eagle.iteye.com/blog/704629 2.https://like-eagle.iteye.com/blog/704629``` 6. What's SQL injection? How to prevent? 7. What ACID(Atomicity, Consistencty, Isolation, Durability)? 8. What's Denormalization? 9. What's filesort? ``` https://blog.csdn.net/yangyu112654374/article/details/4251624 https://www.36nu.com/post/197 ``` 10. What's the N+1 problem? 11. How would you find the most expensive queries in an application? ## Frornted筆試題目 1. Describe TCP, HTTP, HTTPS and WebSocket 2. What is RESTful? 3. What is idempotent operation?```https://ihower.tw/blog/archives/6483``` 4. What is JSONP, CORS? 5. Describe how the browser gets a HTML from server? and how browser renders the html on screen? (step by step) 6. What's non-blocking IO? 7. What's the difference between == and ===? 8. What is thread-safe? 9. When will the browser send a OPTION request to API server? 10. What's XSS? and how to prevent? 11. What's Promise? 12. What's ECMA Script? 13. Difference in var, let and const in JS? 14. What is session and persistent cookies, sessionStorage and localStorage? 15. Describe HTTP caching mechanism. 16. What are the tradeoffs of client-side rendering vs. server-side rendering? 17. What's domain sharding? # JWT https://jwt.io/introduction/ ![](https://i.imgur.com/8WYFMrK.png) ![](https://i.imgur.com/deByl4x.png) ![](https://i.imgur.com/nK7Trfp.png) ![](https://i.imgur.com/rzwpLPY.png) ![](https://i.imgur.com/0zYLX76.png) 想請問一下 token在client端會存在哪裡呢,我聽過一種,我現在也有這樣做 token 拆成 header + payload 與 signeture 放 cookie,header + payload 不用 httponly,但 signeture 加上 httponly 被 XSS 攻擊就是全被偷,拆開的話只會有 header + payload 被偷 只要 payload 沒有隱密資料就不會有問題 如果沒這個要求,全部用 session 放後端比較好 上面有人提到放 cookie + httponly 其實也不好 面試 === 剛剛提到的幾題 1.你的優點缺點 2.甚麼樣的情況會想離職 還有的可能問題 1.怎麼樣才算是一個好開發者 2.舉一個做的比主管預期的還好的經驗 3.為甚麼想進國泰 4.之後的職涯規劃跟走向,能在國泰得到甚麼樣的實現 5.看到公司內部有甚麼問題?是否曾經跟高層溝通過? 6.之前合作經驗有沒有過不順暢的經驗 7.會不會壓力大就想走 二面會分兩個階段: HR+部門 or 部門+HR HR關: 1/簡單自我介紹 2/目前狀況? 3/為甚麼會離開前公司? 4/目前找工作方向 5/為甚麼DDT會吸引你? 6/遇到困難,怎麼解決問題? 7/問薪資 (HR會問初階,因為非核薪HR, 需要講的很詳細) 期望薪資: 115萬,保有討論空間 跨部門主管*3 位 P.S 有點小小的壓力測試,不要被嚇到 喜歡特質: 耐錯性高,不要一個蘿蔔一個坑,積極主動 以情境題來了解人選 1/你覺得做這份工作需要具備那些特質?為甚麼需要這些特質? 2/碰到那些問題讓你比較受挫? 3/碰到溝通上比較不順利會怎麼解決? 4/描述自己的優缺點各三個? 5/跨部門溝通,會怎麼協調? 6/什麼樣的情況,會想讓你離職? 7/什麼樣的主管領導模式,會比較適合你? 8/怎麼跟同事和主管的相處? https://www.ithome.com.tw/article/140997 ```plantuml @startgantt [Prototype design] lasts 15 days [Test prototype] lasts 10 days -- All example -- [Task 1 (1 day)] lasts 1 day [T2 (5 days)] lasts 5 days [T3 (1 week)] lasts 1 week [T4 (1 week and 4 days)] lasts 1 week and 4 days [T5 (2 weeks)] lasts 2 weeks @endgantt ``` 後端工程師招募試券-中/高階 姓名: 基礎觀念: 1. 簡單說明Heap, Stack 記憶體差異 Heap ,用來儲存複雜型別或是指標這種動態配置出來的物件的資料用的. 這裡面的資料會透過程式來手動釋放或特別的標記法標記可清除, 會倍GC給回收. Stack, 用來儲存特定範圍的局部變數用的, 像method中宣告的變數, 在method離開後就會被清除, Stack消除順序是 last in first out的順序在管理. 2. 簡單說明 Process, Thread, Coroutine差異 Process與Thread基本都是OS在負責管理的, Process是資源分配的基本單元, 內部有自己獨立的記憶體空間, 載入執行的程式碼跟系統資源等. Thread則是在Process下的一個輕量執行單元, 一個Process能有多個Thread, 且thread可以共享process內部獨立的記憶體空間的資訊, 跟共享上下文 Coroutine則是程式的動態執行環境鎖構建出來的執行單元, 能夠在同一個thread之間產生好幾個coroutine並且切換或是暫停或執行等操作. 透過這些技術, 軟體系統可以作到并行操作, 同時接收多個工作, 依照狀態做切換, 提高吞吐量. 3. 簡單說明Thread的各種狀態 New → Runnable → Running → Blocked → Waiting → Terminated 4. 簡單說明Thread Scheduler和Time Slicing 5. Mysql(innodb)索引分為哪些類型, 使用的數據結構, 有什麼優缺點 B-tree , 支援範圍查找和排序等等的; 但因為是平衡樹, 當節點數量有異動時需要維護樹的高度與節點間的關係 Hash, 查找與新增效率都是O(1)常數時間, 非常的快, 對於查找單一值是最優的選擇; 但會有碰撞問題需要處理, 也不支援範圍查找和排序, 因為hash本身就無序. 倒序索引, 用來做模糊全文檢索, 但處理上比較慢, 因為要做分詞與更多索引的處理, 且比起B-tree需要的儲存空間更大, 6. 說明Mysql鎖類型, 鎖粒度 類型有shared lock, exclusive lock, intention lock等 shared lock用在讀取上, 允許多個transaction同時讀取一個資源, 但與寫入操作互斥. Exclusive lock則是用在寫入更新上, 當一個transaction需要修改資源時, 會上該鎖, 讓多個要修改同一個資源的transaction們等待 intention lock, 用在transaction若有存取到其他資源時上的lock, 有intention shared 與intention exclusive, 像交易時, 總是會對餘額做確認, 這時就能下for update(IX lock), 但我們的目的可能是寫到order就是了. Lock granularity則是說lock的影響範圍, 有table lock, row lock, page lock. Table locking就是整個表都進行Exclusive lock row locking則是在要被修改或讀取的record上做locking page locking則是在硬碟存取的一個基本單元上整個做locking 7. 如何實現分布式高併發鎖 情境沒很懂 但Redis能透過setnx來實現或是用redis內建的RedLock 或者使用像etcd的TX也能做到 8. 如何解決redis主從架構鎖失效 情境沒很懂 Redis cluster? 或者用上一題講的redlock, 是能在主從架構中實現強一致性的lock 9. 如何提升分布式鎖性能 情境沒很懂 但我想就把鎖的顆粒度變小吧, 這樣才能提供更高的併發操作 Coding: *使用語言不限, 算出結果後請寫上該算法的時間複雜度 1. 請寫出一個函式, 輸入為一陣列lst及常數n, 輸出將lst分成每n個為一組的二維陣列, example: Input: lst = [1, 2, 3, 4, 5], n=2 output: result = [[1, 2], [3, 4], [5]] package main import ( "fmt" ) func groupArray(lst []int, n int) [][]int { length := len(lst) numGroups := length / n if length%n != 0 { numGroups++ } result := make([][]int, numGroups) for i := 0; i < numGroups; i++ { start := i * n end := start + n if end > length { end = length } // 透過slice取需要的範圍 result[i] = lst[start:end] } return result } func main() { lst := []int{1, 2, 3, 4, 5} n := 2 result := groupArray(lst, n) fmt.Println(result) } 2. 請寫出一個函式, 輸入為一整數陣列lst, 找出符合條件的子數組數量, *子數組條件為”數組中不同整數的個數剛好為k” *子數組內容相同,位置不同視為不同子數組,如下 example: Input: lst = [1, 3, 1, 3, 2], k=2 *符合條件的子數組 [1,3], [3,1], [1,3], [3,2], [1,3,1], [3,1,3], [1,3,1,3] output: result = 7 ---- MySQL | thread A | thread B | 結果 | | ---- | ---- |---- | | mysql> BEGIN; | mysql> BEGIN; | | | mysql> INSERT INTO order select 5, `test`; | | 成功 | | | mysql> select * from order; | [{1,'a'},{2,'b'},{3,c},{4,'test'}] | | | mysql> update order set id=id+1; | | | mysql>commit; | | 成功| | | mysql> select * from order; | [{2,'a'},{5,'b'},{5,c},{5,'test'},{6,'test'}] | 為什麼? ---- RabbitMQ 1. 為什麼系統裡要加入MQ? 2. 怎麼確保producer再把資料送檔mq的時候, 不會因為半路遺失而導致資料不見? 3. subscriber又如何確保資料沒丟失, 真的送達他手上? 4. 在這樣的架構下, 怎確保資料的冪等性 ---- 系統題 1. API服務依賴了database或MQ或其他外部服務, 如果再依賴的服務有異常無法服務時, API服務這裡能怎樣處理, 讓服務不會因此而發生聯級效應也跟著崩潰? 2. API服務如果是cluster架構下, 怎對已登入成功的用戶做驗證授權? 你會如何設計. --- Go ```go= package main import "fmt" type query func(string) string func exec(name string, vs ...query) string { ch := make(chan string) fn := func(i int) { ch <- vs[i](name) } for i, _ := range vs { go fn(i) } return <-ch } func main() { ret := exec("111", func(n string) string { return n + "func1" }, func(n string) string { return n + "func2" }, func(n string) string { return n + "func3" }, func(n string) string { return n + "func4" }) fmt.Println(ret) } ``` deadlock 解釋 解釋為什麼印出的數字是那樣? 怎修正? deadlock怎發生的, 怎處理? ```go= package main import ( "fmt" "sync" ) func main() { ch := make(chan *int, 4) array := []int{1, 2, 3, 4} wg := sync.WaitGroup{} wg.Add(1) go func() { for _, value := range array { ch <- &value } }() go func() { for value := range ch { fmt.Println(*value) // what will be printed here? } wg.Done() }() wg.Wait() } ``` ans: 共享變量的指針:在第一個 goroutine 中,&value 是對 value 變量的指針的引用。由於 value 在 for 循環中被重用,所以每次迭代都會更新其地址指向的值。這意味著所有發送到通道 ch 的指針都指向同一個變量 value 的地址。 打印相同的值:當第二個 goroutine 從通道 ch 讀取值時,它實際上讀取的是同一個地址的值。由於第一個 goroutine 在發送所有值之前已經完成了迭代,所以這個地址中的值最終是 4。這就是為什麼打印出四次 4 的原因。 死鎖:死鎖發生是因為第二個 goroutine 在通道 ch 被關閉之前就已經完成了對通道的讀取。但是,通道 ch 從未被顯式關閉,所以第二個 goroutine 會一直等待新的數據,而第一個 goroutine 已經結束了。這導致了死鎖。 ```go= package main import ( "fmt" "sync" ) func main() { ch := make(chan *int, 4) array := []int{1, 2, 3, 4} wg := sync.WaitGroup{} wg.Add(1) go func() { for _, value := range array { val := value // 創建一個副本 ch <- &val } close(ch) // 關閉通道 }() go func() { for value := range ch { fmt.Println(*value) } wg.Done() }() wg.Wait() } ``` ```go= package main import ( "fmt" "sync" ) func main() { ch := make(chan *int, 4) array := []int{1, 2, 3, 4} wg := sync.WaitGroup{} // Add the number of works equal to the number of array elements. wg.Add(len(array)) go func() { for _, value := range array { ch <- &value } }() go func() { for value := range ch { fmt.Println(*value) // Decrement the waitgroup counter with each iteration. wg.Done() } }() wg.Wait() } ``` 會產生deadlock嘛? 為什麼? 怎修正數字正確印出? ```go= package main import ( "fmt" "sync" ) func main() { ch := make(chan *int, 4) array := []int{1, 2, 3, 4} wg := sync.WaitGroup{} wg.Add(1) go func() { for _, value := range array { ch <- &value } }() go func() { for value := range ch { fmt.Println(*value) } wg.Done() }() // New goroutine is run. go func() { var a int for { a++ } }() wg.Wait() } ``` ans: 通道未關閉:在您的代碼中,第一個 goroutine 在發送完數據後並沒有關閉通道 ch。這意味著第二個 goroutine 在讀取完四個數據後會一直等待更多數據。然而,由於有一個無限循環的 goroutine 在運行,程序不會達到完全的死鎖狀態,但第二個 goroutine 會永遠處於等待狀態。 ```go= package main import ( "fmt" "sync" ) func main() { ch := make(chan *int, 4) array := []int{1, 2, 3, 4} wg := sync.WaitGroup{} wg.Add(1) go func() { for _, value := range array { val := value // 創建一個副本 ch <- &val } close(ch) // 關閉通道 }() go func() { for value := range ch { fmt.Println(*value) } wg.Done() }() // 新的無限循環 goroutine go func() { var a int for { a++ } }() wg.Wait() } ``` m個發布者與1個消費者 ```go package main import ( "fmt" "log" "math/rand" "sync" "time" ) // m publishers const numPublishers = 20 // Publisher 發布者 func publisher(dataCh chan<- int, wg *sync.WaitGroup) { defer wg.Done() for { dataCh <- rand.Intn(100) time.Sleep(time.Millisecond * 10) } } // Consumer 消費者 func consumer(dataCh chan int) { for i := 0; i < 100; i++ { // 假設只處理 100 條數據 data := <-dataCh fmt.Printf("Data received: %d\n", data) } close(dataCh) } func main() { dataCh := make(chan int) var wg sync.WaitGroup wg.Add(numPublishers) for i := 0; i < numPublishers; i++ { go publisher(dataCh, &wg) } go consumer(dataCh) wg.Wait() log.Println("bye bye") } ``` ```go= package main import ( "fmt" "math/rand" "sync" "time" ) // m publishers const numPublishers = 20 // Publisher 發布者 func publisher(dataCh chan<- int, stopCh <-chan struct{}, wg *sync.WaitGroup) { defer wg.Done() for { select { case <-stopCh: return default: dataCh <- rand.Intn(100) time.Sleep(time.Millisecond * 10) } } } // Consumer 消費者 func consumer(dataCh chan int) { for i := 0; i < 100; i++ { // 假設只處理 100 條數據 data := <-dataCh fmt.Printf("Data received: %d\n", data) } //close(dataCh) } func main() { dataCh := make(chan int) stopCh := make(chan struct{}) var wg sync.WaitGroup wg.Add(numPublishers) for i := 0; i < numPublishers; i++ { go publisher(dataCh, stopCh, &wg) } go consumer(dataCh) time.Sleep(time.Second * 3) close(stopCh) wg.Wait() close(dataCh) } ```